Skip to content

Commit a2ff58a

Browse files
define QMSolution type (#92)
1 parent 1d9acc3 commit a2ff58a

10 files changed

+69
-77
lines changed

src/QuadraticModels.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ import NLPModelsModifiers: SlackModel, slack_meta
3030

3131
import Base.convert
3232

33-
export AbstractQuadraticModel, QuadraticModel, presolve, postsolve, postsolve!
33+
export AbstractQuadraticModel, QuadraticModel, presolve, postsolve, postsolve!, QMSolution
3434

3535
include("linalg_utils.jl")
3636
include("qpmodel.jl")

src/presolve/empty_rows.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,4 @@ function empty_rows!(
2222
return empty_row_pass
2323
end
2424

25-
postsolve!(pt::OutputPoint, operation::EmptyRow) = nothing
25+
postsolve!(sol::QMSolution, operation::EmptyRow) = nothing

src/presolve/free_rows.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,4 @@ function free_rows!(
2121
return free_row_pass
2222
end
2323

24-
postsolve!(pt::OutputPoint, operation::FreeRow) = nothing
24+
postsolve!(sol::QMSolution, operation::FreeRow) = nothing

src/presolve/linear_singleton_columns.jl

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -81,16 +81,16 @@ function free_linear_singleton_columns!(
8181
return free_lsc_pass, c0 + c0_offset
8282
end
8383

84-
function postsolve!(pt::OutputPoint{T, S}, operation::FreeLinearSingletonColumn{T, S}) where {T, S}
85-
x = pt.x
84+
function postsolve!(sol::QMSolution{T, S}, operation::FreeLinearSingletonColumn{T, S}) where {T, S}
85+
x = sol.x
8686
j = operation.j
8787
# x[j] = (coival - Σₖ Aik x[k]) / Aij , where k ≂̸ j
8888
x[j] = operation.conival
8989
for (i, Aij) in zip(operation.arowi.nzind, operation.arowi.nzval)
9090
x[j] -= Aij * x[i]
9191
end
9292
x[j] /= operation.aij
93-
pt.s_l[j] = zero(T)
94-
pt.s_u[j] = zero(T)
95-
pt.y[operation.i] = operation.yi
93+
sol.s_l[j] = zero(T)
94+
sol.s_u[j] = zero(T)
95+
sol.y[operation.i] = operation.yi
9696
end

src/presolve/postsolve_utils.jl

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,22 @@
1-
function restore_x!(kept_cols, xin::S, xout::S, nvar) where {S}
1+
function restore_x!(kept_cols, x_in::S, x::S, nvar) where {S}
22
# put x and xps inside xout according to kept_cols
33
cx = 0
44
for i = 1:nvar
55
if kept_cols[i]
66
cx += 1
7-
xout[i] = xin[cx]
7+
x[i] = x_in[cx]
88
end
99
end
1010
end
1111

12-
function restore_y!(kept_rows::Vector{Bool}, y::Vector{T}, yout::Vector{T}, ncon) where {T}
12+
function restore_y!(kept_rows::Vector{Bool}, y_in::Vector{T}, y::Vector{T}, ncon) where {T}
1313
c_y = 0
1414
for i = 1:ncon
1515
if !kept_rows[i]
16-
yout[i] = zero(T)
16+
y[i] = zero(T)
1717
else
1818
c_y += 1
19-
yout[i] = y[c_y]
19+
y[i] = y_in[c_y]
2020
end
2121
end
2222
end

src/presolve/presolve.jl

Lines changed: 30 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
11
abstract type PresolveOperation{T, S} end
22

3-
mutable struct OutputPoint{T, S}
3+
"""
4+
Type used to define a solution point when using [`postsolve`](@ref).
5+
6+
sol = QMSolution(x, y, s_l, s_u)
7+
8+
where `s_l` and `s_u` should be of type `SparseVector`.
9+
"""
10+
mutable struct QMSolution{T, S}
411
x::S
512
y::S
613
s_l::SparseVector{T, Int}
@@ -347,49 +354,46 @@ end
347354
function postsolve!(
348355
qm::QuadraticModel{T, S},
349356
psqm::PresolvedQuadraticModel{T, S},
350-
pt_out::OutputPoint{T, S},
351-
x_in::S,
352-
y_in::S,
357+
sol::QMSolution{T, S},
358+
sol_in::QMSolution{T, S},
353359
) where {T, S}
360+
x_in, y_in = sol_in.x, sol_in.y
354361
n_operations = length(psqm.psd.operations)
355-
nvar = length(pt_out.x)
356-
restore_x!(psqm.psd.kept_cols, x_in, pt_out.x, nvar)
357-
ncon = length(pt_out.y)
358-
restore_y!(psqm.psd.kept_rows, y_in, pt_out.y, ncon)
362+
nvar = length(sol.x)
363+
restore_x!(psqm.psd.kept_cols, x_in, sol.x, nvar)
364+
ncon = length(sol.y)
365+
restore_y!(psqm.psd.kept_rows, y_in, sol.y, ncon)
359366
for i = n_operations:-1:1
360367
operation_i = psqm.psd.operations[i]
361-
postsolve!(pt_out, operation_i)
368+
postsolve!(sol, operation_i)
362369
end
363370
end
364371

365372
"""
366-
pt = postsolve(qm::QuadraticModel{T, S}, psqm::PresolvedQuadraticModel{T, S},
367-
x_in::S, y_in::S,
368-
s_l_in::SparseVector{T, Int},
369-
s_u_in::SparseVector{T, Int}) where {T, S}
373+
sol = postsolve(qm::QuadraticModel{T, S}, psqm::PresolvedQuadraticModel{T, S},
374+
sol_in::QMSolution{T, S}) where {T, S}
370375
371-
Retrieve the solution `(x, y, s_l, s_u)` of the original QP `qm` given the solution of the presolved QP (`psqm`)
372-
`x_in, y_in, s_l_in, s_u_in`.
376+
Retrieve the solution `sol = (x, y, s_l, s_u)` of the original QP `qm` given the solution of the presolved QP (`psqm`)
377+
`sol_in` of type [`QMSolution`](@ref).
373378
"""
374379
function postsolve(
375380
qm::QuadraticModel{T, S},
376381
psqm::PresolvedQuadraticModel{T, S},
377-
x_in::S,
378-
y_in::S,
379-
s_l::SparseVector{T, Int},
380-
s_u::SparseVector{T, Int},
382+
sol_in::QMSolution{T, S},
381383
) where {T, S}
382-
x_out = similar(qm.meta.x0)
383-
y_out = similar(qm.meta.y0)
384+
x = similar(qm.meta.x0)
385+
y = similar(qm.meta.y0)
386+
s_l = sol_in.s_l
387+
s_u = sol_in.s_u
384388

385389
ilow, iupp = s_l.nzind, s_u.nzind
386390
restore_ilow_iupp!(ilow, iupp, psqm.psd.kept_cols)
387-
pt_out = OutputPoint(
388-
x_out,
389-
y_out,
391+
sol = QMSolution(
392+
x,
393+
y,
390394
SparseVector(qm.meta.nvar, ilow, s_l.nzval),
391395
SparseVector(qm.meta.nvar, iupp, s_u.nzval),
392396
)
393-
postsolve!(qm, psqm, pt_out, x_in, y_in)
394-
return pt_out
397+
postsolve!(qm, psqm, sol, sol_in)
398+
return sol
395399
end

src/presolve/remove_ifix.jl

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -87,15 +87,15 @@ function remove_ifix!(
8787
return c0ps, ifix_pass
8888
end
8989

90-
function postsolve!(pt::OutputPoint{T, S}, operation::RemoveIfix{T, S}) where {T, S}
90+
function postsolve!(sol::QMSolution{T, S}, operation::RemoveIfix{T, S}) where {T, S}
9191
j = operation.j
92-
pt.x[j] = operation.xj
93-
ATyj = @views dot(operation.acolj.nzval, pt.y[operation.acolj.nzind])
94-
Hxj = @views dot(operation.hcolj.nzval, pt.x[operation.hcolj.nzind])
92+
sol.x[j] = operation.xj
93+
ATyj = @views dot(operation.acolj.nzval, sol.y[operation.acolj.nzind])
94+
Hxj = @views dot(operation.hcolj.nzval, sol.x[operation.hcolj.nzind])
9595
s = operation.cj + Hxj - ATyj
9696
if s > zero(T)
97-
pt.s_l[j] = s
97+
sol.s_l[j] = s
9898
else
99-
pt.s_u[j] = -s
99+
sol.s_u[j] = -s
100100
end
101101
end

src/presolve/singleton_rows.jl

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -63,19 +63,19 @@ function singleton_rows!(
6363
return singl_row_pass
6464
end
6565

66-
function postsolve!(pt::OutputPoint{T, S}, operation::SingletonRow{T, S}) where {T, S}
66+
function postsolve!(sol::QMSolution{T, S}, operation::SingletonRow{T, S}) where {T, S}
6767
i, j = operation.i, operation.j
6868
Aij = operation.Aij
69-
pt.y[i] = zero(T)
69+
sol.y[i] = zero(T)
7070
if operation.tightened_lvar
71-
pt.y[i] += pt.s_l[j] / Aij
72-
pt.s_l[j] = zero(T)
71+
sol.y[i] += sol.s_l[j] / Aij
72+
sol.s_l[j] = zero(T)
7373
end
7474
if operation.tightened_uvar
75-
pt.y[i] -= pt.s_u[j] / Aij
76-
pt.s_u[j] = zero(T)
75+
sol.y[i] -= sol.s_u[j] / Aij
76+
sol.s_u[j] = zero(T)
7777
end
7878
if !operation.tightened_lvar && !operation.tightened_uvar
79-
pt.y[i] = zero(T)
79+
sol.y[i] = zero(T)
8080
end
8181
end

src/presolve/unconstrained_reductions.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,4 +41,4 @@ function unconstrained_reductions!(
4141
return unbounded
4242
end
4343

44-
postsolve!(pt::OutputPoint, operation::UnconstrainedReduction) = nothing
44+
postsolve!(sol::QMSolution, operation::UnconstrainedReduction) = nothing

test/test_presolve.jl

Lines changed: 12 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -48,12 +48,9 @@
4848
@test psqp.meta.ifix == Int[]
4949
@test psqp.meta.nvar == 2
5050

51-
x_in = [4.0; 7.0]
52-
y_in = [2.0; 2.0]
53-
s_l = sparse([3.0; 2.0])
54-
s_u = sparse([0.0; 0.0])
55-
pt_out = postsolve(qp, psqp, x_in, y_in, s_l, s_u)
56-
@test pt_out.x == [4.0; 2.0; 7.0]
51+
sol_in = QMSolution([4.0; 7.0], [2.0; 2.0], sparse([3.0; 2.0]), sparse([0.0; 0.0]))
52+
sol = postsolve(qp, psqp, sol_in)
53+
@test sol.x == [4.0; 2.0; 7.0]
5754

5855
# test that solves the problem
5956
qp2 = QuadraticModel(
@@ -113,12 +110,9 @@ end
113110
@test psqp.meta.lcon == psqp.meta.ucon == bps_true
114111
@test psqp.meta.ncon == 3
115112

116-
x_in = [4.0; 7.0; 4.0]
117-
y_in = [2.0; 2.0; 4.0]
118-
s_l = sparse([3.0; 4.0; 2.0])
119-
s_u = sparse([0.0; 3.0; 0.0])
120-
pt_out = postsolve(qp, psqp, x_in, y_in, s_l, s_u)
121-
@test pt_out.y == [2.0; 0.0; 0.0; 2.0; 0.0; 4.0]
113+
sol_in = QMSolution([4.0; 7.0; 4.0], [2.0; 2.0; 4.0], sparse([3.0; 4.0; 2.0]), sparse([0.0; 3.0; 0.0]))
114+
sol = postsolve(qp, psqp, sol_in)
115+
@test sol.y == [2.0; 0.0; 0.0; 2.0; 0.0; 4.0]
122116
end
123117

124118
@testset "presolve singleton rows" begin
@@ -165,12 +159,9 @@ end
165159
@test Aps == sparse(Aps_true)
166160
@test psqp.meta.ncon == 2
167161

168-
x_in = [4.0; 7.0; 4.0]
169-
y_in = [2.0; 4.0]
170-
s_l = sparse([3.0; 4.0; 2.0])
171-
s_u = sparse([0.0; 3.0; 0.0])
172-
pt_out = postsolve(qp, psqp, x_in, y_in, s_l, s_u)
173-
@test pt_out.y == [2.0; 0.0; 0.0; 1.0; 0.0; 4.0]
162+
sol_in = QMSolution([4.0; 7.0; 4.0], [2.0; 4.0], sparse([3.0; 4.0; 2.0]), sparse([0.0; 3.0; 0.0]))
163+
sol = postsolve(qp, psqp, sol_in)
164+
@test sol.y == [2.0; 0.0; 0.0; 1.0; 0.0; 4.0]
174165
end
175166

176167
@testset "presolve singleton rows and ifix" begin
@@ -239,10 +230,7 @@ end
239230
statsps = presolve(qp)
240231
psqp = statsps.solver_specific[:presolvedQM]
241232

242-
x_in = [4.0; 4.0]
243-
y_in = [2.0; 4.0]
244-
s_l = sparse([3.0; 2.0])
245-
s_u = sparse([0.0; 0.0])
246-
pt_out = postsolve(qp, psqp, x_in, y_in, s_l, s_u)
247-
@test pt_out.x [4.0, -2.5, 4.0]
233+
sol_in = QMSolution([4.0; 4.0], [2.0; 4.0], sparse([3.0; 2.0]), sparse([0.0; 0.0]))
234+
sol = postsolve(qp, psqp, sol_in)
235+
@test sol.x [4.0, -2.5, 4.0]
248236
end

0 commit comments

Comments
 (0)