From 72c442dbd4a5b571d5e3629e06e415fb54b7c334 Mon Sep 17 00:00:00 2001 From: Alexis Montoison Date: Fri, 16 May 2025 00:23:46 -0500 Subject: [PATCH 1/8] Add a structure LinearModel --- ext/QuadraticModelsQPSReaderExt.jl | 15 +++ src/QuadraticModels.jl | 3 +- src/lpmodel.jl | 210 +++++++++++++++++++++++++++++ src/qpmodel.jl | 45 +++---- 4 files changed, 243 insertions(+), 30 deletions(-) create mode 100644 src/lpmodel.jl diff --git a/ext/QuadraticModelsQPSReaderExt.jl b/ext/QuadraticModelsQPSReaderExt.jl index c1a721b..a43cb5d 100644 --- a/ext/QuadraticModelsQPSReaderExt.jl +++ b/ext/QuadraticModelsQPSReaderExt.jl @@ -21,4 +21,19 @@ function QuadraticModels.QuadraticModel(qps::QPSReader.QPSData, x0 = zeros(qps.n ) end +function QuadraticModels.LinearModel(qps::QPSReader.QPSData, x0 = zeros(qps.nvar)) + QuadraticModels.LinearModel( + qps.c, + Arows = qps.arows, + Acols = qps.acols, + Avals = qps.avals, + lcon = qps.lcon, + ucon = qps.ucon, + lvar = qps.lvar, + uvar = qps.uvar, + c0 = qps.c0, + x0 = x0, + ) +end + end diff --git a/src/QuadraticModels.jl b/src/QuadraticModels.jl index 4dfca2c..414120f 100644 --- a/src/QuadraticModels.jl +++ b/src/QuadraticModels.jl @@ -27,10 +27,11 @@ import NLPModelsModifiers: SlackModel, slack_meta import Base.convert -export AbstractQuadraticModel, QuadraticModel, presolve, postsolve, postsolve!, QMSolution +export AbstractQuadraticModel, LinearModel, QuadraticModel, presolve, postsolve, postsolve!, QMSolution include("linalg_utils.jl") include("qpmodel.jl") +include("lpmodel.jl") include("presolve/presolve.jl") end # module diff --git a/src/lpmodel.jl b/src/lpmodel.jl new file mode 100644 index 0000000..29c40a1 --- /dev/null +++ b/src/lpmodel.jl @@ -0,0 +1,210 @@ +""" + lp = LinearModel(c; Arows = Arows, Acols = Acols, Avals = Avals, + lcon = lcon, ucon = ucon, lvar = lvar, uvar = uvar, c0=c0, sortcols = false) + + lp = LinearModel(c; A = A, lcon = lcon, ucon = ucon, lvar = lvar, uvar = uvar, c0 = c0) + +Create a Linear model ``min ~c^T x + c_0`` with optional bounds +`lvar ≦ x ≦ uvar` and optional linear constraints `lcon ≦ Ax ≦ ucon`. + +With the first constructor, if `sortcols = true`, then `Acols` is sorted in ascending order +(`Arows` and `Avals` are then sorted accordingly). + +You can also use [`QPSReader.jl`](https://github.com/JuliaSmoothOptimizers/QPSReader.jl) to +create a Linear model from a QPS file: + + using QPSReader + qps = readqps("QAFIRO.SIF") + lp = LinearModel(qps) +""" +mutable struct LinearModel{T, S, M1, M2} <: AbstractQuadraticModel{T, S} + meta::NLPModelMeta{T, S} + counters::Counters + data::QPData{T, S, M1, M2} +end + +function LinearModel( + c::S; + Arows::AbstractVector{<:Integer} = Int[], + Acols::AbstractVector{<:Integer} = Int[], + Avals::S = S(undef, 0), + lcon::S = S(undef, 0), + ucon::S = S(undef, 0), + lvar::S = fill!(S(undef, length(c)), eltype(c)(-Inf)), + uvar::S = fill!(S(undef, length(c)), eltype(c)(Inf)), + c0::T = zero(eltype(c)), + sortcols::Bool = false, + kwargs..., +) where {T, S} + @assert all(lvar .≤ uvar) + @assert all(lcon .≤ ucon) + nnzh = 0 + nnzj = length(Avals) + if !(nnzj == length(Arows) == length(Acols)) + error("The length of Arows, Acols and Avals must be the same") + end + ncon = length(lcon) + if ncon != length(ucon) + error("The length of lcon and ucon must be the same") + end + nvar = length(c) + if !(nvar == length(lvar) == length(uvar)) + error("The length of c, lvar and uvar must be the same") + end + if sortcols + pA = sortperm(Acols) + permute!(Arows, pA) + permute!(Acols, pA) + permute!(Avals, pA) + end + LinearModel( + NLPModelMeta{T, S}( + length(c), + lvar = lvar, + uvar = uvar, + ncon = ncon, + lcon = lcon, + ucon = ucon, + nnzj = nnzj, + lin_nnzj = nnzj, + nln_nnzj = 0, + nnzh = nnzh, + lin = 1:ncon, + islp = true; + kwargs..., + ), + Counters(), + QPData( + c0, + c, + SparseMatrixCOO(0, nvar, similar(Arows, 0), similar(Acols, 0), similar(Avals, 0)), + SparseMatrixCOO(ncon, nvar, Arows, Acols, Avals), + ), + ) +end + +function LinearModel( + c::S; + A::Union{AbstractMatrix{T}, AbstractLinearOperator{T}} = SparseMatrixCOO(0, length(c), Int[], Int[], T[]), + lcon::S = S(undef, 0), + ucon::S = S(undef, 0), + lvar::S = fill!(S(undef, length(c)), T(-Inf)), + uvar::S = fill!(S(undef, length(c)), T(Inf)), + c0::T = zero(T), + kwargs..., +) where {T, S} + @assert all(lvar .≤ uvar) + @assert all(lcon .≤ ucon) + ncon, nvar = size(A) + nnzh = 0 + nnzj = nnz(A) + H = similar_empty_matrix(A, length(c)) + data = QPData(c0, c, H, A) + + LinearModel( + NLPModelMeta{T, S}( + nvar, + lvar = lvar, + uvar = uvar, + ncon = ncon, + lcon = lcon, + ucon = ucon, + nnzj = nnzj, + lin_nnzj = nnzj, + nln_nnzj = 0, + nnzh = nnzh, + lin = 1:ncon, + islp = (ncon == 0); + kwargs..., + ), + Counters(), + data, + ) +end + +""" + LinearModel(nlp, x) + +Creates a linear Taylor model of `nlp` around `x`. +""" +function LinearModel(model::AbstractNLPModel{T, S}, x::AbstractVector; kwargs...) where {T, S} + nvar = model.meta.nvar + ncon = model.meta.ncon + c0 = obj(model, x) + g = grad(model, x) + if model.meta.ncon > 0 + c = cons(model, x) + Arows, Acols = jac_structure(model) + Avals = jac_coord(model, x) + LinearModel( + g, + c0 = c0, + Arows = Arows, + Acols = Acols, + Avals = Avals, + lcon = model.meta.lcon .- c, + ucon = model.meta.ucon .- c, + lvar = model.meta.lvar .- x, + uvar = model.meta.uvar .- x, + x0 = fill!(S(undef, model.meta.nvar), zero(T)), + ) + else + LinearModel( + g, + c0 = c0, + lvar = model.meta.lvar .- x, + uvar = model.meta.uvar .- x, + x0 = fill!(S(undef, model.meta.nvar), zero(T)), + ) + end +end + +function NLPModels.objgrad!(qp::LinearModel, x::AbstractVector, g::AbstractVector) + NLPModels.increment!(qp, :neval_obj) + NLPModels.increment!(qp, :neval_grad) + f = qp.data.c0 + dot(qp.data.c, x) + g .+= qp.data.c + return f, g +end + +function NLPModels.obj(qp::LinearModel, x::AbstractVector) + NLPModels.increment!(qp, :neval_obj) + return qp.data.c0 + dot(qp.data.c, x) +end + +function NLPModels.grad!(qp::LinearModel, x::AbstractVector, g::AbstractVector) + NLPModels.increment!(qp, :neval_grad) + g .= qp.data.c + return g +end + +function NLPModels.hess_structure!( + lp::LinearModel, + rows::AbstractVector{<:Integer}, + cols::AbstractVector{<:Integer}, +) + return rows, cols +end + +function NLPModels.hess_coord!( + lp::LinearModel, + x::AbstractVector, + vals::AbstractVector; + obj_weight::Real = one(eltype(x)), +) + NLPModels.increment!(lp, :neval_hess) + fill!(vals, zero(eltype(x))) + return vals +end + +function NLPModels.hprod!( + lp::LinearModel, + x::AbstractVector, + v::AbstractVector, + Hv::AbstractVector; + obj_weight::Real = one(eltype(x)), +) + NLPModels.increment!(lp, :neval_hprod) + fill!(Hv, zero(eltype(x))) + return Hv +end diff --git a/src/qpmodel.jl b/src/qpmodel.jl index 6ace079..261d44d 100644 --- a/src/qpmodel.jl +++ b/src/qpmodel.jl @@ -13,7 +13,7 @@ mutable struct QPData{ A::M2 end -@inline QPData(c0, c, H, A) = QPData(c0, c, similar(c), H, A) +QPData(c0, c, H, A) = QPData(c0, c, similar(c), H, A) isdense(data::QPData{T, S, M1, M2}) where {T, S, M1, M2} = M1 <: DenseMatrix || M2 <: DenseMatrix function Base.convert( @@ -33,9 +33,9 @@ abstract type AbstractQuadraticModel{T, S} <: AbstractNLPModel{T, S} end """ qp = QuadraticModel(c, Hrows, Hcols, Hvals; Arows = Arows, Acols = Acols, Avals = Avals, - lcon = lcon, ucon = ucon, lvar = lvar, uvar = uvar, sortcols = false) + lcon = lcon, ucon = ucon, lvar = lvar, uvar = uvar, c0 = c0, sortcols = false) - qp = QuadraticModel(c, H; A = A, lcon = lcon, ucon = ucon, lvar = lvar, uvar = uvar) + qp = QuadraticModel(c, H; A = A, lcon = lcon, ucon = ucon, lvar = lvar, uvar = uvar, c0 = c0) Create a Quadratic model ``min ~\\tfrac{1}{2} x^T H x + c^T x + c_0`` with optional bounds `lvar ≦ x ≦ uvar` and optional linear constraints `lcon ≦ Ax ≦ ucon`. @@ -137,7 +137,7 @@ function QuadraticModel( nln_nnzj = 0, nnzh = nnzh, lin = 1:ncon, - islp = (ncon == 0); + islp = (nnzh == 0); kwargs..., ), Counters(), @@ -184,7 +184,7 @@ function QuadraticModel( nvar, lvar = lvar, uvar = uvar, - ncon = size(A, 1), + ncon = ncon, lcon = lcon, ucon = ucon, nnzj = nnzj, @@ -247,22 +247,22 @@ end linobj(qp::AbstractQuadraticModel, args...) = qp.data.c -function NLPModels.objgrad!(qp::AbstractQuadraticModel, x::AbstractVector, g::AbstractVector) +function NLPModels.objgrad!(qp::QuadraticModel, x::AbstractVector, g::AbstractVector) NLPModels.increment!(qp, :neval_obj) NLPModels.increment!(qp, :neval_grad) mul!(g, Symmetric(qp.data.H, :L), x) f = qp.data.c0 + dot(qp.data.c, x) + dot(g, x) / 2 - @. g .+= qp.data.c + g .+= qp.data.c return f, g end -function NLPModels.obj(qp::AbstractQuadraticModel{T, S}, x::AbstractVector) where {T, S} +function NLPModels.obj(qp::QuadraticModel, x::AbstractVector) NLPModels.increment!(qp, :neval_obj) mul!(qp.data.v, Symmetric(qp.data.H, :L), x) return qp.data.c0 + dot(qp.data.c, x) + dot(qp.data.v, x) / 2 end -function NLPModels.grad!(qp::AbstractQuadraticModel, x::AbstractVector, g::AbstractVector) +function NLPModels.grad!(qp::QuadraticModel, x::AbstractVector, g::AbstractVector) NLPModels.increment!(qp, :neval_grad) mul!(g, Symmetric(qp.data.H, :L), x) g .+= qp.data.c @@ -363,7 +363,7 @@ function NLPModels.hess_coord!( end NLPModels.hess_coord!( - qp::QuadraticModel, + qp::AbstractQuadraticModel, x::AbstractVector, y::AbstractVector, vals::AbstractVector; @@ -392,7 +392,7 @@ function NLPModels.jac_lin_structure!( end function NLPModels.jac_lin_structure!( - qp::QuadraticModel{T, S, M1, M2}, + qp::AbstractQuadraticModel{T, S, M1, M2}, rows::AbstractVector{<:Integer}, cols::AbstractVector{<:Integer}, ) where {T, S, M1, M2 <: Matrix} @@ -409,7 +409,7 @@ function NLPModels.jac_lin_structure!( end function NLPModels.jac_lin_coord!( - qp::QuadraticModel{T, S, M1, M2}, + qp::AbstractQuadraticModel{T, S, M1, M2}, x::AbstractVector, vals::AbstractVector, ) where {T, S, M1, M2 <: SparseMatrixCOO} @@ -421,7 +421,7 @@ function NLPModels.jac_lin_coord!( end function NLPModels.jac_lin_coord!( - qp::QuadraticModel{T, S, M1, M2}, + qp::AbstractQuadraticModel{T, S, M1, M2}, x::AbstractVector, vals::AbstractVector, ) where {T, S, M1, M2 <: SparseMatrixCSC} @@ -433,7 +433,7 @@ function NLPModels.jac_lin_coord!( end function NLPModels.jac_lin_coord!( - qp::QuadraticModel{T, S, M1, M2}, + qp::AbstractQuadraticModel{T, S, M1, M2}, x::AbstractVector, vals::AbstractVector, ) where {T, S, M1, M2 <: Matrix} @@ -451,7 +451,7 @@ function NLPModels.jac_lin_coord!( end function NLPModels.jac_lin( - qp::QuadraticModel{T, S, M1, M2}, + qp::AbstractQuadraticModel{T, S, M1, M2}, x::AbstractVector, ) where {T, S, M1 <: AbstractLinearOperator, M2 <: AbstractLinearOperator} @lencheck qp.meta.nvar x @@ -468,7 +468,7 @@ function NLPModels.cons_lin!(qp::AbstractQuadraticModel, x::AbstractVector, c::A end function NLPModels.hprod!( - qp::AbstractQuadraticModel, + qp::QuadraticModel, x::AbstractVector, v::AbstractVector, Hv::AbstractVector; @@ -504,19 +504,6 @@ function NLPModels.jprod_lin!( return Av end -function NLPModels.jtprod!( - qp::AbstractQuadraticModel, - x::AbstractVector, - v::AbstractVector, - Atv::AbstractVector, -) - @lencheck qp.meta.nvar x Atv - @lencheck qp.meta.ncon v - NLPModels.increment!(qp, :neval_jtprod) - mul!(Atv, transpose(qp.data.A), v) - return Atv -end - function NLPModels.jtprod_lin!( qp::AbstractQuadraticModel, x::AbstractVector, From e848ef34c85e19f1ba1eec3f91133f465344f144 Mon Sep 17 00:00:00 2001 From: Alexis Montoison Date: Fri, 16 May 2025 00:26:42 -0500 Subject: [PATCH 2/8] Fix islp --- src/lpmodel.jl | 2 +- src/qpmodel.jl | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lpmodel.jl b/src/lpmodel.jl index 29c40a1..034f86c 100644 --- a/src/lpmodel.jl +++ b/src/lpmodel.jl @@ -114,7 +114,7 @@ function LinearModel( nln_nnzj = 0, nnzh = nnzh, lin = 1:ncon, - islp = (ncon == 0); + islp = true; kwargs..., ), Counters(), diff --git a/src/qpmodel.jl b/src/qpmodel.jl index 261d44d..0ff584a 100644 --- a/src/qpmodel.jl +++ b/src/qpmodel.jl @@ -192,7 +192,7 @@ function QuadraticModel( nln_nnzj = 0, nnzh = nnzh, lin = 1:ncon, - islp = (ncon == 0); + islp = (nnzh == 0); kwargs..., ), Counters(), From 208757fb20dbe059c404c209e36cf9faccbe8323 Mon Sep 17 00:00:00 2001 From: Alexis Montoison Date: Fri, 16 May 2025 00:36:01 -0500 Subject: [PATCH 3/8] Fix islp --- src/lpmodel.jl | 4 ++-- src/qpmodel.jl | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/lpmodel.jl b/src/lpmodel.jl index 034f86c..4ada504 100644 --- a/src/lpmodel.jl +++ b/src/lpmodel.jl @@ -99,7 +99,7 @@ function LinearModel( nnzh = 0 nnzj = nnz(A) H = similar_empty_matrix(A, length(c)) - data = QPData(c0, c, H, A) + data = QPData(c0, c, H, A; lp=true) LinearModel( NLPModelMeta{T, S}( @@ -163,7 +163,7 @@ function NLPModels.objgrad!(qp::LinearModel, x::AbstractVector, g::AbstractVecto NLPModels.increment!(qp, :neval_obj) NLPModels.increment!(qp, :neval_grad) f = qp.data.c0 + dot(qp.data.c, x) - g .+= qp.data.c + g .= qp.data.c return f, g end diff --git a/src/qpmodel.jl b/src/qpmodel.jl index 0ff584a..092409c 100644 --- a/src/qpmodel.jl +++ b/src/qpmodel.jl @@ -13,7 +13,7 @@ mutable struct QPData{ A::M2 end -QPData(c0, c, H, A) = QPData(c0, c, similar(c), H, A) +QPData(c0, c, H, A; lp::Bool=false) = QPData(c0, c, lp ? similar(c): similar(c, 0), H, A) isdense(data::QPData{T, S, M1, M2}) where {T, S, M1, M2} = M1 <: DenseMatrix || M2 <: DenseMatrix function Base.convert( @@ -29,7 +29,7 @@ Base.convert( data::QPData{T, S, M1, M2}, ) where {T, S, M1 <: SparseMatrixCOO, M2 <: SparseMatrixCOO, MCOO <: SparseMatrixCOO{T}} = data -abstract type AbstractQuadraticModel{T, S} <: AbstractNLPModel{T, S} end +abstract type AbstractQuadraticModel{T, S, M1, M2} <: AbstractNLPModel{T, S} end """ qp = QuadraticModel(c, Hrows, Hcols, Hvals; Arows = Arows, Acols = Acols, Avals = Avals, @@ -137,7 +137,7 @@ function QuadraticModel( nln_nnzj = 0, nnzh = nnzh, lin = 1:ncon, - islp = (nnzh == 0); + islp = false; kwargs..., ), Counters(), @@ -192,7 +192,7 @@ function QuadraticModel( nln_nnzj = 0, nnzh = nnzh, lin = 1:ncon, - islp = (nnzh == 0); + islp = false; kwargs..., ), Counters(), From 1a0dd3af7b4a7d8b2012cf5e3238895512a5b3da Mon Sep 17 00:00:00 2001 From: Alexis Montoison Date: Fri, 16 May 2025 00:38:11 -0500 Subject: [PATCH 4/8] Fix typo... --- src/qpmodel.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qpmodel.jl b/src/qpmodel.jl index 092409c..e3ebd1f 100644 --- a/src/qpmodel.jl +++ b/src/qpmodel.jl @@ -13,7 +13,7 @@ mutable struct QPData{ A::M2 end -QPData(c0, c, H, A; lp::Bool=false) = QPData(c0, c, lp ? similar(c): similar(c, 0), H, A) +QPData(c0, c, H, A; lp::Bool=false) = QPData(c0, c, lp ? similar(c, 0) : similar(c), H, A) isdense(data::QPData{T, S, M1, M2}) where {T, S, M1, M2} = M1 <: DenseMatrix || M2 <: DenseMatrix function Base.convert( From 160d3a4c74034cad11df0dc760338e65e86a12a0 Mon Sep 17 00:00:00 2001 From: Alexis Montoison Date: Fri, 16 May 2025 00:44:24 -0500 Subject: [PATCH 5/8] Fix typo... --- src/lpmodel.jl | 2 +- src/presolve/presolve.jl | 2 +- src/qpmodel.jl | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/lpmodel.jl b/src/lpmodel.jl index 4ada504..6a3dc76 100644 --- a/src/lpmodel.jl +++ b/src/lpmodel.jl @@ -17,7 +17,7 @@ create a Linear model from a QPS file: qps = readqps("QAFIRO.SIF") lp = LinearModel(qps) """ -mutable struct LinearModel{T, S, M1, M2} <: AbstractQuadraticModel{T, S} +mutable struct LinearModel{T, S, M1, M2} <: AbstractQuadraticModel{T, S, M1, M2} meta::NLPModelMeta{T, S} counters::Counters data::QPData{T, S, M1, M2} diff --git a/src/presolve/presolve.jl b/src/presolve/presolve.jl index a6f70c9..fe8250f 100644 --- a/src/presolve/presolve.jl +++ b/src/presolve/presolve.jl @@ -137,7 +137,7 @@ include("primal_constraints.jl") include("free_rows.jl") include("postsolve_utils.jl") -mutable struct PresolvedQuadraticModel{T, S, M1, M2} <: AbstractQuadraticModel{T, S} +mutable struct PresolvedQuadraticModel{T, S, M1, M2} <: AbstractQuadraticModel{T, S, M1, M2} meta::NLPModelMeta{T, S} counters::Counters data::QPData{T, S, M1, M2} diff --git a/src/qpmodel.jl b/src/qpmodel.jl index e3ebd1f..54ed6c5 100644 --- a/src/qpmodel.jl +++ b/src/qpmodel.jl @@ -66,7 +66,7 @@ based on a `QPData` with dense matrices will convert the field `data` to a `QPDa Its in-place variant `SlackModel!` specific to QuadraticModels will only work with a `QuadraticModel` based on a `QPData` with SparseMatricesCOO. """ -mutable struct QuadraticModel{T, S, M1, M2} <: AbstractQuadraticModel{T, S} +mutable struct QuadraticModel{T, S, M1, M2} <: AbstractQuadraticModel{T, S, M1, M2} meta::NLPModelMeta{T, S} counters::Counters data::QPData{T, S, M1, M2} From 460ec8cee671e995bd7f0cbe1f561efbe399bb30 Mon Sep 17 00:00:00 2001 From: Alexis Montoison Date: Mon, 19 May 2025 00:14:26 -0500 Subject: [PATCH 6/8] Improve the support of LP problems --- ext/QuadraticModelsQPSReaderExt.jl | 15 -- src/QuadraticModels.jl | 3 +- src/lpmodel.jl | 210 -------------------------- src/qpmodel.jl | 234 +++++++++++++++++++++++------ 4 files changed, 189 insertions(+), 273 deletions(-) delete mode 100644 src/lpmodel.jl diff --git a/ext/QuadraticModelsQPSReaderExt.jl b/ext/QuadraticModelsQPSReaderExt.jl index a43cb5d..c1a721b 100644 --- a/ext/QuadraticModelsQPSReaderExt.jl +++ b/ext/QuadraticModelsQPSReaderExt.jl @@ -21,19 +21,4 @@ function QuadraticModels.QuadraticModel(qps::QPSReader.QPSData, x0 = zeros(qps.n ) end -function QuadraticModels.LinearModel(qps::QPSReader.QPSData, x0 = zeros(qps.nvar)) - QuadraticModels.LinearModel( - qps.c, - Arows = qps.arows, - Acols = qps.acols, - Avals = qps.avals, - lcon = qps.lcon, - ucon = qps.ucon, - lvar = qps.lvar, - uvar = qps.uvar, - c0 = qps.c0, - x0 = x0, - ) -end - end diff --git a/src/QuadraticModels.jl b/src/QuadraticModels.jl index 414120f..4dfca2c 100644 --- a/src/QuadraticModels.jl +++ b/src/QuadraticModels.jl @@ -27,11 +27,10 @@ import NLPModelsModifiers: SlackModel, slack_meta import Base.convert -export AbstractQuadraticModel, LinearModel, QuadraticModel, presolve, postsolve, postsolve!, QMSolution +export AbstractQuadraticModel, QuadraticModel, presolve, postsolve, postsolve!, QMSolution include("linalg_utils.jl") include("qpmodel.jl") -include("lpmodel.jl") include("presolve/presolve.jl") end # module diff --git a/src/lpmodel.jl b/src/lpmodel.jl deleted file mode 100644 index 6a3dc76..0000000 --- a/src/lpmodel.jl +++ /dev/null @@ -1,210 +0,0 @@ -""" - lp = LinearModel(c; Arows = Arows, Acols = Acols, Avals = Avals, - lcon = lcon, ucon = ucon, lvar = lvar, uvar = uvar, c0=c0, sortcols = false) - - lp = LinearModel(c; A = A, lcon = lcon, ucon = ucon, lvar = lvar, uvar = uvar, c0 = c0) - -Create a Linear model ``min ~c^T x + c_0`` with optional bounds -`lvar ≦ x ≦ uvar` and optional linear constraints `lcon ≦ Ax ≦ ucon`. - -With the first constructor, if `sortcols = true`, then `Acols` is sorted in ascending order -(`Arows` and `Avals` are then sorted accordingly). - -You can also use [`QPSReader.jl`](https://github.com/JuliaSmoothOptimizers/QPSReader.jl) to -create a Linear model from a QPS file: - - using QPSReader - qps = readqps("QAFIRO.SIF") - lp = LinearModel(qps) -""" -mutable struct LinearModel{T, S, M1, M2} <: AbstractQuadraticModel{T, S, M1, M2} - meta::NLPModelMeta{T, S} - counters::Counters - data::QPData{T, S, M1, M2} -end - -function LinearModel( - c::S; - Arows::AbstractVector{<:Integer} = Int[], - Acols::AbstractVector{<:Integer} = Int[], - Avals::S = S(undef, 0), - lcon::S = S(undef, 0), - ucon::S = S(undef, 0), - lvar::S = fill!(S(undef, length(c)), eltype(c)(-Inf)), - uvar::S = fill!(S(undef, length(c)), eltype(c)(Inf)), - c0::T = zero(eltype(c)), - sortcols::Bool = false, - kwargs..., -) where {T, S} - @assert all(lvar .≤ uvar) - @assert all(lcon .≤ ucon) - nnzh = 0 - nnzj = length(Avals) - if !(nnzj == length(Arows) == length(Acols)) - error("The length of Arows, Acols and Avals must be the same") - end - ncon = length(lcon) - if ncon != length(ucon) - error("The length of lcon and ucon must be the same") - end - nvar = length(c) - if !(nvar == length(lvar) == length(uvar)) - error("The length of c, lvar and uvar must be the same") - end - if sortcols - pA = sortperm(Acols) - permute!(Arows, pA) - permute!(Acols, pA) - permute!(Avals, pA) - end - LinearModel( - NLPModelMeta{T, S}( - length(c), - lvar = lvar, - uvar = uvar, - ncon = ncon, - lcon = lcon, - ucon = ucon, - nnzj = nnzj, - lin_nnzj = nnzj, - nln_nnzj = 0, - nnzh = nnzh, - lin = 1:ncon, - islp = true; - kwargs..., - ), - Counters(), - QPData( - c0, - c, - SparseMatrixCOO(0, nvar, similar(Arows, 0), similar(Acols, 0), similar(Avals, 0)), - SparseMatrixCOO(ncon, nvar, Arows, Acols, Avals), - ), - ) -end - -function LinearModel( - c::S; - A::Union{AbstractMatrix{T}, AbstractLinearOperator{T}} = SparseMatrixCOO(0, length(c), Int[], Int[], T[]), - lcon::S = S(undef, 0), - ucon::S = S(undef, 0), - lvar::S = fill!(S(undef, length(c)), T(-Inf)), - uvar::S = fill!(S(undef, length(c)), T(Inf)), - c0::T = zero(T), - kwargs..., -) where {T, S} - @assert all(lvar .≤ uvar) - @assert all(lcon .≤ ucon) - ncon, nvar = size(A) - nnzh = 0 - nnzj = nnz(A) - H = similar_empty_matrix(A, length(c)) - data = QPData(c0, c, H, A; lp=true) - - LinearModel( - NLPModelMeta{T, S}( - nvar, - lvar = lvar, - uvar = uvar, - ncon = ncon, - lcon = lcon, - ucon = ucon, - nnzj = nnzj, - lin_nnzj = nnzj, - nln_nnzj = 0, - nnzh = nnzh, - lin = 1:ncon, - islp = true; - kwargs..., - ), - Counters(), - data, - ) -end - -""" - LinearModel(nlp, x) - -Creates a linear Taylor model of `nlp` around `x`. -""" -function LinearModel(model::AbstractNLPModel{T, S}, x::AbstractVector; kwargs...) where {T, S} - nvar = model.meta.nvar - ncon = model.meta.ncon - c0 = obj(model, x) - g = grad(model, x) - if model.meta.ncon > 0 - c = cons(model, x) - Arows, Acols = jac_structure(model) - Avals = jac_coord(model, x) - LinearModel( - g, - c0 = c0, - Arows = Arows, - Acols = Acols, - Avals = Avals, - lcon = model.meta.lcon .- c, - ucon = model.meta.ucon .- c, - lvar = model.meta.lvar .- x, - uvar = model.meta.uvar .- x, - x0 = fill!(S(undef, model.meta.nvar), zero(T)), - ) - else - LinearModel( - g, - c0 = c0, - lvar = model.meta.lvar .- x, - uvar = model.meta.uvar .- x, - x0 = fill!(S(undef, model.meta.nvar), zero(T)), - ) - end -end - -function NLPModels.objgrad!(qp::LinearModel, x::AbstractVector, g::AbstractVector) - NLPModels.increment!(qp, :neval_obj) - NLPModels.increment!(qp, :neval_grad) - f = qp.data.c0 + dot(qp.data.c, x) - g .= qp.data.c - return f, g -end - -function NLPModels.obj(qp::LinearModel, x::AbstractVector) - NLPModels.increment!(qp, :neval_obj) - return qp.data.c0 + dot(qp.data.c, x) -end - -function NLPModels.grad!(qp::LinearModel, x::AbstractVector, g::AbstractVector) - NLPModels.increment!(qp, :neval_grad) - g .= qp.data.c - return g -end - -function NLPModels.hess_structure!( - lp::LinearModel, - rows::AbstractVector{<:Integer}, - cols::AbstractVector{<:Integer}, -) - return rows, cols -end - -function NLPModels.hess_coord!( - lp::LinearModel, - x::AbstractVector, - vals::AbstractVector; - obj_weight::Real = one(eltype(x)), -) - NLPModels.increment!(lp, :neval_hess) - fill!(vals, zero(eltype(x))) - return vals -end - -function NLPModels.hprod!( - lp::LinearModel, - x::AbstractVector, - v::AbstractVector, - Hv::AbstractVector; - obj_weight::Real = one(eltype(x)), -) - NLPModels.increment!(lp, :neval_hprod) - fill!(Hv, zero(eltype(x))) - return Hv -end diff --git a/src/qpmodel.jl b/src/qpmodel.jl index 54ed6c5..cb3d02f 100644 --- a/src/qpmodel.jl +++ b/src/qpmodel.jl @@ -39,11 +39,20 @@ abstract type AbstractQuadraticModel{T, S, M1, M2} <: AbstractNLPModel{T, S} end Create a Quadratic model ``min ~\\tfrac{1}{2} x^T H x + c^T x + c_0`` with optional bounds `lvar ≦ x ≦ uvar` and optional linear constraints `lcon ≦ Ax ≦ ucon`. + The user should only give the lower triangle of `H` to the `QuadraticModel` constructor. With the first constructor, if `sortcols = true`, then `Hcols` and `Acols` are sorted in ascending order (`Hrows`, `Hvals` and `Arows`, `Avals` are then sorted accordingly). + lp = QuadraticModel(c, Arows, Acols, Avals; + lcon = lcon, ucon = ucon, lvar = lvar, uvar = uvar, c0 = c0, sortcols = false) + + lp = QuadraticModel(c, A; lcon = lcon, ucon = ucon, lvar = lvar, uvar = uvar, c0 = c0) + +Create a Linear model ``c^T x + c_0`` with linear constraints `lcon ≦ Ax ≦ ucon` and +optional bounds `lvar ≦ x ≦ uvar` and . + You can also use [`QPSReader.jl`](https://github.com/JuliaSmoothOptimizers/QPSReader.jl) to create a Quadratic model from a QPS file: @@ -95,7 +104,7 @@ function QuadraticModel( c0::T = zero(eltype(c)), sortcols::Bool = false, kwargs..., -) where {T, S} +) where {T, S <: AbstractVector{T}} @assert all(lvar .≤ uvar) @assert all(lcon .≤ ucon) nnzh = length(Hvals) @@ -146,6 +155,68 @@ function QuadraticModel( c, SparseMatrixCOO(nvar, nvar, Hrows, Hcols, Hvals), SparseMatrixCOO(ncon, nvar, Arows, Acols, Avals), + lp = false, + ), + ) +end + + +function QuadraticModel( + c::S, + Arows::AbstractVector{<:Integer}, + Acols::AbstractVector{<:Integer}, + Avals::S; + lcon::S = S(undef, 0), + ucon::S = S(undef, 0), + lvar::S = fill!(S(undef, length(c)), eltype(c)(-Inf)), + uvar::S = fill!(S(undef, length(c)), eltype(c)(Inf)), + c0::T = zero(eltype(c)), + sortcols::Bool = false, + kwargs..., +) where {T, S <: AbstractVector{T}} + @assert all(lvar .≤ uvar) + @assert all(lcon .≤ ucon) + nnzj = length(Avals) + if !(nnzj == length(Arows) == length(Acols)) + error("The length of Arows, Acols and Avals must be the same") + end + ncon = length(lcon) + if ncon != length(ucon) + error("The length of lcon and ucon must be the same") + end + nvar = length(c) + if !(nvar == length(lvar) == length(uvar)) + error("The length of c, lvar and uvar must be the same") + end + if sortcols + pA = sortperm(Acols) + permute!(Arows, pA) + permute!(Acols, pA) + permute!(Avals, pA) + end + QuadraticModel( + NLPModelMeta{T, S}( + length(c), + lvar = lvar, + uvar = uvar, + ncon = ncon, + lcon = lcon, + ucon = ucon, + nnzj = nnzj, + lin_nnzj = nnzj, + nln_nnzj = 0, + nnzh = 0, + lin = 1:ncon, + islp = true; + kwargs..., + ), + Counters(), + QPData( + c0, + c, + SparseMatrixCOO(nvar, nvar, Int[], Int[], T[]), + SparseMatrixCOO(ncon, nvar, Arows, Acols, Avals), + lp = true, ), ) end @@ -165,18 +236,18 @@ function QuadraticModel( uvar::S = fill!(S(undef, length(c)), T(Inf)), c0::T = zero(T), kwargs..., -) where {T, S} +) where {T, S <: AbstractVector{T}} @assert all(lvar .≤ uvar) @assert all(lcon .≤ ucon) ncon, nvar = size(A) if typeof(H) <: AbstractLinearOperator # convert A to a LinOp if A is a Matrix? nnzh = 0 nnzj = 0 - data = QPData(c0, c, H, A) + data = QPData(c0, c, H, A; lp=false) else nnzh = typeof(H) <: DenseMatrix ? nvar * (nvar + 1) / 2 : nnz(H) nnzj = nnz(A) - data = typeof(H) <: Symmetric ? QPData(c0, c, H.data, A) : QPData(c0, c, H, A) + data = typeof(H) <: Symmetric ? QPData(c0, c, H.data, A) : QPData(c0, c, H, A; lp=false) end QuadraticModel( @@ -200,12 +271,55 @@ function QuadraticModel( ) end + +function QuadraticModel( + c::S, + A::Union{AbstractMatrix{T}, AbstractLinearOperator{T}}; + lcon::S = S(undef, 0), + ucon::S = S(undef, 0), + lvar::S = fill!(S(undef, length(c)), T(-Inf)), + uvar::S = fill!(S(undef, length(c)), T(Inf)), + c0::T = zero(T), + kwargs..., +) where {T, S <: AbstractVector{T}} + @assert all(lvar .≤ uvar) + @assert all(lcon .≤ ucon) + ncon, nvar = size(A) + if typeof(A) <: AbstractLinearOperator # convert A to a LinOp if A is a Matrix? + nnzj = 0 + else + nnzj = nnz(A) + end + H = SparseMatrixCOO(nvar, nvar, Int[], Int[], T[]) + data = QPData(c0, c, H, A; lp=false) + + QuadraticModel( + NLPModelMeta{T, S}( + nvar, + lvar = lvar, + uvar = uvar, + ncon = ncon, + lcon = lcon, + ucon = ucon, + nnzj = nnzj, + lin_nnzj = nnzj, + nln_nnzj = 0, + nnzh = 0, + lin = 1:ncon, + islp = true; + kwargs..., + ), + Counters(), + data, + ) +end + """ QuadraticModel(nlp, x) Creates a quadratic Taylor model of `nlp` around `x`. """ -function QuadraticModel(model::AbstractNLPModel{T, S}, x::AbstractVector; kwargs...) where {T, S} +function QuadraticModel(model::AbstractNLPModel{T, S}, x::AbstractVector; kwargs...) where {T, S <: AbstractVector{T}} nvar = model.meta.nvar ncon = model.meta.ncon c0 = obj(model, x) @@ -250,37 +364,41 @@ linobj(qp::AbstractQuadraticModel, args...) = qp.data.c function NLPModels.objgrad!(qp::QuadraticModel, x::AbstractVector, g::AbstractVector) NLPModels.increment!(qp, :neval_obj) NLPModels.increment!(qp, :neval_grad) - mul!(g, Symmetric(qp.data.H, :L), x) - f = qp.data.c0 + dot(qp.data.c, x) + dot(g, x) / 2 - g .+= qp.data.c + if qp.meta.islp + f = qp.data.c0 + dot(qp.data.c, x) + g .= qp.data.c + else + mul!(g, Symmetric(qp.data.H, :L), x) + f = qp.data.c0 + dot(qp.data.c, x) + dot(g, x) / 2 + g .+= qp.data.c + end return f, g end function NLPModels.obj(qp::QuadraticModel, x::AbstractVector) NLPModels.increment!(qp, :neval_obj) - mul!(qp.data.v, Symmetric(qp.data.H, :L), x) - return qp.data.c0 + dot(qp.data.c, x) + dot(qp.data.v, x) / 2 + if qp.meta.islp + f = qp.data.c0 + dot(qp.data.c, x) + else + mul!(qp.data.v, Symmetric(qp.data.H, :L), x) + f = qp.data.c0 + dot(qp.data.c, x) + dot(qp.data.v, x) / 2 + end + return f end function NLPModels.grad!(qp::QuadraticModel, x::AbstractVector, g::AbstractVector) NLPModels.increment!(qp, :neval_grad) - mul!(g, Symmetric(qp.data.H, :L), x) - g .+= qp.data.c + if qp.meta.islp + g .= qp.data.c + else + mul!(g, Symmetric(qp.data.H, :L), x) + g .+= qp.data.c + end return g end # TODO: Better hess_op -function NLPModels.hess_structure!( - qp::QuadraticModel{T, S, M1}, - rows::AbstractVector{<:Integer}, - cols::AbstractVector{<:Integer}, -) where {T, S, M1 <: SparseMatrixCOO} - rows .= qp.data.H.rows - cols .= qp.data.H.cols - return rows, cols -end - function fill_structure!(S::SparseMatrixCSC, rows, cols) count = 1 @inbounds for col = 1:size(S, 2), k = S.colptr[col]:(S.colptr[col + 1] - 1) @@ -290,12 +408,16 @@ function fill_structure!(S::SparseMatrixCSC, rows, cols) end end -function fill_coord!(S::SparseMatrixCSC, vals, obj_weight) - count = 1 - @inbounds for col = 1:size(S, 2), k = S.colptr[col]:(S.colptr[col + 1] - 1) - vals[count] = obj_weight * S.nzval[k] - count += 1 +function NLPModels.hess_structure!( + qp::QuadraticModel{T, S, M1}, + rows::AbstractVector{<:Integer}, + cols::AbstractVector{<:Integer}, +) where {T, S, M1 <: SparseMatrixCOO} + if !qp.meta.islp + rows .= qp.data.H.rows + cols .= qp.data.H.cols end + return rows, cols end function NLPModels.hess_structure!( @@ -303,7 +425,9 @@ function NLPModels.hess_structure!( rows::AbstractVector{<:Integer}, cols::AbstractVector{<:Integer}, ) where {T, S, M1 <: SparseMatrixCSC} - fill_structure!(qp.data.H, rows, cols) + if !qp.meta.islp + fill_structure!(qp.data.H, rows, cols) + end return rows, cols end @@ -312,17 +436,27 @@ function NLPModels.hess_structure!( rows::AbstractVector{<:Integer}, cols::AbstractVector{<:Integer}, ) where {T, S, M1 <: Matrix} - count = 1 - for j = 1:(qp.meta.nvar) - for i = j:(qp.meta.nvar) - rows[count] = i - cols[count] = j - count += 1 + if !qp.meta.islp + count = 1 + for j = 1:(qp.meta.nvar) + for i = j:(qp.meta.nvar) + rows[count] = i + cols[count] = j + count += 1 + end end end return rows, cols end +function fill_coord!(S::SparseMatrixCSC, vals, obj_weight) + count = 1 + @inbounds for col = 1:size(S, 2), k = S.colptr[col]:(S.colptr[col + 1] - 1) + vals[count] = obj_weight * S.nzval[k] + count += 1 + end +end + function NLPModels.hess_coord!( qp::QuadraticModel{T, S, M1}, x::AbstractVector{T}, @@ -330,7 +464,9 @@ function NLPModels.hess_coord!( obj_weight::Real = one(eltype(x)), ) where {T, S, M1 <: SparseMatrixCOO} NLPModels.increment!(qp, :neval_hess) - vals .= obj_weight .* qp.data.H.vals + if !qp.meta.islp + vals .= obj_weight .* qp.data.H.vals + end return vals end @@ -341,7 +477,9 @@ function NLPModels.hess_coord!( obj_weight::Real = one(eltype(x)), ) where {T, S, M1 <: SparseMatrixCSC} NLPModels.increment!(qp, :neval_hess) - fill_coord!(qp.data.H, vals, obj_weight) + if !qp.meta.islp + fill_coord!(qp.data.H, vals, obj_weight) + end return vals end @@ -352,11 +490,13 @@ function NLPModels.hess_coord!( obj_weight::Real = one(eltype(x)), ) where {T, S, M1 <: Matrix} NLPModels.increment!(qp, :neval_hess) - count = 1 - for j = 1:(qp.meta.nvar) - for i = j:(qp.meta.nvar) - vals[count] = obj_weight * qp.data.H[i, j] - count += 1 + if !qp.meta.islp + count = 1 + for j = 1:(qp.meta.nvar) + for i = j:(qp.meta.nvar) + vals[count] = obj_weight * qp.data.H[i, j] + count += 1 + end end end return vals @@ -382,7 +522,7 @@ function NLPModels.jac_lin_structure!( end function NLPModels.jac_lin_structure!( - qp::QuadraticModel{T, S, M1, M2}, + qp::AbstractQuadraticModel{T, S, M1, M2}, rows::AbstractVector{<:Integer}, cols::AbstractVector{<:Integer}, ) where {T, S, M1, M2 <: SparseMatrixCSC} @@ -475,9 +615,11 @@ function NLPModels.hprod!( obj_weight::Real = one(eltype(x)), ) NLPModels.increment!(qp, :neval_hprod) - mul!(Hv, Symmetric(qp.data.H, :L), v) - if obj_weight != 1 - Hv .*= obj_weight + if !qp.meta.islp + mul!(Hv, Symmetric(qp.data.H, :L), v) + if obj_weight != 1 + Hv .*= obj_weight + end end return Hv end @@ -588,7 +730,7 @@ end function NLPModelsModifiers.SlackModel( qp::AbstractQuadraticModel{T, S}, name = qp.meta.name * "-slack", -) where {T, S} +) where {T, S <: AbstractVector{T}} qp.meta.ncon == length(qp.meta.jfix) && return qp nfix = length(qp.meta.jfix) ns = qp.meta.ncon - nfix From 591304bcf7fea76937359ed4d2c233bb5e01ecef Mon Sep 17 00:00:00 2001 From: Alexis Montoison Date: Mon, 19 May 2025 00:21:16 -0500 Subject: [PATCH 7/8] Update qpmodel.jl --- src/qpmodel.jl | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/qpmodel.jl b/src/qpmodel.jl index cb3d02f..3c5956e 100644 --- a/src/qpmodel.jl +++ b/src/qpmodel.jl @@ -361,7 +361,7 @@ end linobj(qp::AbstractQuadraticModel, args...) = qp.data.c -function NLPModels.objgrad!(qp::QuadraticModel, x::AbstractVector, g::AbstractVector) +function NLPModels.objgrad!(qp::AbstractQuadraticModel, x::AbstractVector, g::AbstractVector) NLPModels.increment!(qp, :neval_obj) NLPModels.increment!(qp, :neval_grad) if qp.meta.islp @@ -375,7 +375,7 @@ function NLPModels.objgrad!(qp::QuadraticModel, x::AbstractVector, g::AbstractVe return f, g end -function NLPModels.obj(qp::QuadraticModel, x::AbstractVector) +function NLPModels.obj(qp::AbstractQuadraticModel, x::AbstractVector) NLPModels.increment!(qp, :neval_obj) if qp.meta.islp f = qp.data.c0 + dot(qp.data.c, x) @@ -386,7 +386,7 @@ function NLPModels.obj(qp::QuadraticModel, x::AbstractVector) return f end -function NLPModels.grad!(qp::QuadraticModel, x::AbstractVector, g::AbstractVector) +function NLPModels.grad!(qp::AbstractQuadraticModel, x::AbstractVector, g::AbstractVector) NLPModels.increment!(qp, :neval_grad) if qp.meta.islp g .= qp.data.c @@ -409,7 +409,7 @@ function fill_structure!(S::SparseMatrixCSC, rows, cols) end function NLPModels.hess_structure!( - qp::QuadraticModel{T, S, M1}, + qp::AbstractQuadraticModel{T, S, M1}, rows::AbstractVector{<:Integer}, cols::AbstractVector{<:Integer}, ) where {T, S, M1 <: SparseMatrixCOO} @@ -421,7 +421,7 @@ function NLPModels.hess_structure!( end function NLPModels.hess_structure!( - qp::QuadraticModel{T, S, M1}, + qp::AbstractQuadraticModel{T, S, M1}, rows::AbstractVector{<:Integer}, cols::AbstractVector{<:Integer}, ) where {T, S, M1 <: SparseMatrixCSC} @@ -432,7 +432,7 @@ function NLPModels.hess_structure!( end function NLPModels.hess_structure!( - qp::QuadraticModel{T, S, M1}, + qp::AbstractQuadraticModel{T, S, M1}, rows::AbstractVector{<:Integer}, cols::AbstractVector{<:Integer}, ) where {T, S, M1 <: Matrix} @@ -458,7 +458,7 @@ function fill_coord!(S::SparseMatrixCSC, vals, obj_weight) end function NLPModels.hess_coord!( - qp::QuadraticModel{T, S, M1}, + qp::AbstractQuadraticModel{T, S, M1}, x::AbstractVector{T}, vals::AbstractVector{T}; obj_weight::Real = one(eltype(x)), @@ -471,7 +471,7 @@ function NLPModels.hess_coord!( end function NLPModels.hess_coord!( - qp::QuadraticModel{T, S, M1}, + qp::AbstractQuadraticModel{T, S, M1}, x::AbstractVector{T}, vals::AbstractVector{T}; obj_weight::Real = one(eltype(x)), @@ -484,7 +484,7 @@ function NLPModels.hess_coord!( end function NLPModels.hess_coord!( - qp::QuadraticModel{T, S, M1}, + qp::AbstractQuadraticModel{T, S, M1}, x::AbstractVector{T}, vals::AbstractVector{T}; obj_weight::Real = one(eltype(x)), @@ -511,7 +511,7 @@ NLPModels.hess_coord!( ) = hess_coord!(qp, x, vals, obj_weight = obj_weight) function NLPModels.jac_lin_structure!( - qp::QuadraticModel{T, S, M1, M2}, + qp::AbstractQuadraticModell{T, S, M1, M2}, rows::AbstractVector{<:Integer}, cols::AbstractVector{<:Integer}, ) where {T, S, M1, M2 <: SparseMatrixCOO} @@ -608,7 +608,7 @@ function NLPModels.cons_lin!(qp::AbstractQuadraticModel, x::AbstractVector, c::A end function NLPModels.hprod!( - qp::QuadraticModel, + qp::AbstractQuadraticModel, x::AbstractVector, v::AbstractVector, Hv::AbstractVector; From e57f6513e20a12c886716982ef768771725599cb Mon Sep 17 00:00:00 2001 From: Alexis Montoison Date: Mon, 19 May 2025 15:11:51 -0500 Subject: [PATCH 8/8] Fix a typo --- src/qpmodel.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/qpmodel.jl b/src/qpmodel.jl index 3c5956e..51577ca 100644 --- a/src/qpmodel.jl +++ b/src/qpmodel.jl @@ -51,7 +51,7 @@ With the first constructor, if `sortcols = true`, then `Hcols` and `Acols` are s lp = QuadraticModel(c, A; lcon = lcon, ucon = ucon, lvar = lvar, uvar = uvar, c0 = c0) Create a Linear model ``c^T x + c_0`` with linear constraints `lcon ≦ Ax ≦ ucon` and -optional bounds `lvar ≦ x ≦ uvar` and . +optional bounds `lvar ≦ x ≦ uvar`. You can also use [`QPSReader.jl`](https://github.com/JuliaSmoothOptimizers/QPSReader.jl) to create a Quadratic model from a QPS file: @@ -511,7 +511,7 @@ NLPModels.hess_coord!( ) = hess_coord!(qp, x, vals, obj_weight = obj_weight) function NLPModels.jac_lin_structure!( - qp::AbstractQuadraticModell{T, S, M1, M2}, + qp::AbstractQuadraticModel{T, S, M1, M2}, rows::AbstractVector{<:Integer}, cols::AbstractVector{<:Integer}, ) where {T, S, M1, M2 <: SparseMatrixCOO}