Skip to content
This repository was archived by the owner on Jun 14, 2020. It is now read-only.

Commit 8ce934a

Browse files
authored
A struct for CSRMatrix (#17)
Add a new CSRMatrix{T} struct to overcome ambiguity relating to the lots of different length vector inputs to the solver facing methods. It is not intended to be a fully-fledged matrix type so it is not a subtype of AbstractSparseMatrix.
1 parent d1ff1ae commit 8ce934a

File tree

6 files changed

+84
-54
lines changed

6 files changed

+84
-54
lines changed

src/constraints.jl

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -152,14 +152,37 @@ function MOI.get(m::LinQuadOptimizer, ::Type{MOI.ConstraintIndex{F,S}}, name::St
152152
m.constraint_names_rev[name]::MOI.ConstraintIndex{F,S}
153153
end
154154

155+
156+
"""
157+
CSRMatrix{T}
158+
159+
Matrix given in compressed sparse row (CSR) format.
160+
161+
`CSRMatrix` is analgous to the structure in Julia's `SparseMatrixCSC` but with
162+
the rows and columns flipped. It contains three vectors:
163+
- `row_pointers` is a vector pointing to the start of each row in
164+
`columns` and `coefficients`;
165+
- `columns` is a vector of column numbers; and
166+
- `coefficients` is a vector of corresponding nonzero values.
167+
168+
The length of `row_pointers` is the number of rows in the matrix.
169+
170+
This struct is not a subtype of `AbstractSparseMatrix` as it is intended to be a
171+
collection of the three vectors as they are required by solvers such as Gurobi.
172+
It is not intended to be used for general computation.
173+
"""
174+
struct CSRMatrix{T}
175+
row_pointers::Vector{Int}
176+
columns::Vector{Int}
177+
coefficients::Vector{T}
178+
function CSRMatrix{T}(row_pointers, columns, coefficients) where T
179+
@assert length(columns) == length(coefficients)
180+
new(row_pointers, columns, coefficients)
181+
end
182+
end
183+
155184
#=
156185
Below we add constraints.
157-
158-
- addconstraint!
159-
- delete!
160-
- get(m, ConstraintSet(), c)
161-
- get(m, ConstraintFunction(), c)
162-
- modifyconstraint!
163186
=#
164187

165188
include("constraints/singlevariable.jl")

src/constraints/scalaraffine.jl

Lines changed: 23 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@ end
2929
function addlinearconstraint!(m::LinQuadOptimizer, func::Linear, set::IV)
3030
columns = [getcol(m, term.variable_index) for term in func.terms]
3131
coefficients = [term.coefficient for term in func.terms]
32-
add_ranged_constraints!(m, [1], columns, coefficients, [set.lower], [set.upper])
32+
A = CSRMatrix{Float64}([1], columns, coefficients)
33+
add_ranged_constraints!(m, A, [set.lower], [set.upper])
3334
end
3435

3536
function addlinearconstraint!(m::LinQuadOptimizer, func::Linear, sense::Cchar, rhs)
@@ -38,7 +39,8 @@ function addlinearconstraint!(m::LinQuadOptimizer, func::Linear, sense::Cchar, r
3839
end
3940
columns = [getcol(m, term.variable_index) for term in func.terms]
4041
coefficients = [term.coefficient for term in func.terms]
41-
add_linear_constraints!(m, [1], columns, coefficients, [sense], [rhs - func.constant])
42+
A = CSRMatrix{Float64}([1], columns, coefficients)
43+
add_linear_constraints!(m, A, [sense], [rhs - func.constant])
4244
end
4345

4446
#=
@@ -83,19 +85,20 @@ function addlinearconstraints!(m::LinQuadOptimizer, func::Vector{Linear}, set::V
8385
end
8486
nnz += length(f.terms)
8587
end
86-
row_starts = Vector{Int}(length(func)) # index of start of each row
87-
column_indices = Vector{Int}(nnz) # flattened columns for each function
88-
coefficients = Vector{Float64}(nnz) # corresponding non-zeros
88+
row_pointers = Vector{Int}(length(func)) # index of start of each row
89+
columns = Vector{Int}(nnz) # flattened columns for each function
90+
coefficients = Vector{Float64}(nnz) # corresponding non-zeros
8991
i = 1
9092
for (fi, f) in enumerate(func)
91-
row_starts[fi] = i
93+
row_pointers[fi] = i
9294
for term in f.terms
93-
column_indices[i] = getcol(m, term.variable_index)
94-
coefficients[i] = term.coefficient
95+
columns[i] = getcol(m, term.variable_index)
96+
coefficients[i] = term.coefficient
9597
i += 1
9698
end
9799
end
98-
add_ranged_constraints!(m, row_starts, column_indices, coefficients, lowerbounds, upperbounds)
100+
A = CSRMatrix{Float64}(row_pointers, columns, coefficients)
101+
add_ranged_constraints!(m, A, lowerbounds, upperbounds)
99102
end
100103

101104
function addlinearconstraints!(m::LinQuadOptimizer, func::Vector{Linear}, sense::Vector{Cchar}, rhs::Vector{Float64})
@@ -108,19 +111,20 @@ function addlinearconstraints!(m::LinQuadOptimizer, func::Vector{Linear}, sense:
108111
end
109112
nnz += length(f.terms)
110113
end
111-
rowbegins = Vector{Int}(length(func)) # index of start of each row
112-
column_indices = Vector{Int}(nnz) # flattened columns for each function
113-
nnz_vals = Vector{Float64}(nnz) # corresponding non-zeros
114-
cnt = 1
115-
for (fi, f) in enumerate(func)
116-
rowbegins[fi] = cnt
114+
row_pointers = Vector{Int}(length(func)) # index of start of each row
115+
columns = Vector{Int}(nnz) # flattened columns for each function
116+
coefficients = Vector{Float64}(nnz) # corresponding non-zeros
117+
i = 1
118+
for (row, f) in enumerate(func)
119+
row_pointers[row] = i
117120
for term in f.terms
118-
column_indices[cnt] = getcol(m, term.variable_index)
119-
nnz_vals[cnt] = term.coefficient
120-
cnt += 1
121+
columns[i] = getcol(m, term.variable_index)
122+
coefficients[i] = term.coefficient
123+
i += 1
121124
end
122125
end
123-
add_linear_constraints!(m, rowbegins, column_indices, nnz_vals, sense, rhs)
126+
A = CSRMatrix{Float64}(row_pointers, columns, coefficients)
127+
add_linear_constraints!(m, A, sense, rhs)
124128
end
125129

126130
#=

src/constraints/vectoraffine.jl

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,9 @@ function MOI.addconstraint!(m::LinQuadOptimizer, func::VecLin, set::S) where S <
2626
end
2727

2828
function addlinearconstraint!(m::LinQuadOptimizer, func::VecLin, sense::Cchar)
29-
outputindex = [term.output_index for term in func.terms]
30-
columns = [getcol(m, term.scalar_term.variable_index) for term in func.terms]
31-
coefficients = [term.scalar_term.coefficient for term in func.terms]
29+
outputindex = [term.output_index for term in func.terms]
30+
columns = [getcol(m, term.scalar_term.variable_index) for term in func.terms]
31+
coefficients = [term.scalar_term.coefficient for term in func.terms]
3232
# sort into row order
3333
pidx = sortperm(outputindex)
3434
permute!(columns, pidx)
@@ -37,16 +37,17 @@ function addlinearconstraint!(m::LinQuadOptimizer, func::VecLin, sense::Cchar)
3737
# check that there is at least a RHS for each row
3838
@assert maximum(outputindex) <= length(func.constants)
3939
# loop through to get starting position of each row
40-
rowbegins = Vector{Int}(length(func.constants))
41-
rowbegins[1] = 1
42-
cnt = 1
40+
row_pointers = Vector{Int}(length(func.constants))
41+
row_pointers[1] = 1
42+
row = 1
4343
for i in 2:length(pidx)
4444
if outputindex[pidx[i]] != outputindex[pidx[i-1]]
45-
cnt += 1
46-
rowbegins[cnt] = i
45+
row += 1
46+
row_pointers[row] = i
4747
end
4848
end
49-
add_linear_constraints!(m, rowbegins, columns, coefficients, fill(sense, length(func.constants)), -func.constants)
49+
A = CSRMatrix{Float64}(row_pointers, columns, coefficients)
50+
add_linear_constraints!(m, A, fill(sense, length(func.constants)), -func.constants)
5051
end
5152

5253
MOI.canmodifyconstraint(m::LinQuadOptimizer, ::VLCI{<: VecLinSets}, ::Type{MOI.VectorConstantChange{Float64}}) = true

src/constraints/vectorofvariables.jl

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,11 @@ function MOI.addconstraint!(m::LinQuadOptimizer, func::VecVar, set::S) where S <
2121
ref = VVCI{S}(m.last_constraint_reference)
2222
rows = get_number_linear_constraints(m)
2323
n = MOI.dimension(set)
24-
add_linear_constraints!(m, collect(1:n), getcol.(m, func.variables), ones(n), fill(backend_type(m, set),n), zeros(n))
24+
add_linear_constraints!(m,
25+
CSRMatrix{Float64}(collect(1:n), getcol.(m, func.variables), ones(n)),
26+
fill(backend_type(m, set),n),
27+
zeros(n)
28+
)
2529
dict = constrdict(m, ref)
2630
dict[ref] = collect(rows+1:rows+n)
2731
append!(m.constraint_primal_solution, fill(NaN,n))

src/mockoptimizer.jl

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@ mutable struct LinQuadSOS
55
end
66

77
mutable struct MockLinQuadModel # <: LinQuadOptInterface.LinQuadOptimizer
8-
8+
99
sense::Symbol
10-
10+
1111
A::Matrix{Float64}
1212
b::Vector{Float64}
1313
c::Vector{Float64}
@@ -20,14 +20,14 @@ mutable struct MockLinQuadModel # <: LinQuadOptInterface.LinQuadOptimizer
2020
ub::Vector{Float64}
2121

2222
vartype::Vector{Cchar} # :Bin, :Int, :Con
23-
contype::Vector{Cchar} # :LEQ :GEQ, :EQ, :RANGE
23+
contype::Vector{Cchar} # :LEQ :GEQ, :EQ, :RANGE
2424

2525
# sos::LinQuadSOS{LinQuadSOS}
2626

2727
termination_status::MOI.TerminationStatusCode
2828
primal_status::MOI.ResultStatusCode
2929
dual_status::MOI.ResultStatusCode
30-
30+
3131
variable_primal_solution::Vector{Float64}
3232
variable_dual_solution::Vector{Float64}
3333

@@ -212,12 +212,13 @@ function LQOI.get_number_linear_constraints(instance::MockLinQuadOptimizer)
212212
size(instance.inner.A)[1]
213213
end
214214

215-
function LQOI.add_linear_constraints!(instance::MockLinQuadOptimizer, rowvec, colvec, coefvec, sensevec, rhsvec)
215+
function LQOI.add_linear_constraints!(instance::MockLinQuadOptimizer, A::CSRMatrix{Float64}, sensevec, rhsvec)
216+
rowvec, colvec, coefvec = A.row_pointers, A.columns, A.coefficients
216217

217218
rows = length(rhsvec)
218219
cols = size(instance.inner.A)[2]
219220
push!(rowvec,length(colvec)+1)
220-
221+
221222
# An = full(sparse(rowvec,colvec,coefvec,rows,cols))
222223
# @show cols,rows,rowvec,colvec,coefvec
223224
An = full(SparseMatrixCSC(cols,rows,rowvec,colvec,coefvec)')
@@ -231,11 +232,12 @@ function LQOI.add_linear_constraints!(instance::MockLinQuadOptimizer, rowvec, co
231232
nothing
232233
end
233234

234-
function LQOI.add_ranged_constraints!(instance::MockLinQuadOptimizer, rowvec, colvec, coefvec, rhsvec, ubvec)
235+
function LQOI.add_ranged_constraints!(instance::MockLinQuadOptimizer, A::CSRMatrix{Float64}, rhsvec, ubvec)
236+
rowvec, colvec, coefvec = A.row_pointers, A.columns, A.coefficients
235237
rows = length(rhsvec)
236238
cols = size(instance.inner.A)[2]
237239
push!(rowvec,length(colvec)+1)
238-
240+
239241
# An = full(sparse(rowvec,colvec,coefvec,rows,cols))
240242
# @show cols,rows,rowvec,colvec,coefvec
241243
An = full(SparseMatrixCSC(cols,rows,rowvec,colvec,coefvec)')
@@ -565,4 +567,4 @@ function hasprimalray(instance::MockLinQuadOptimizer)
565567
end
566568
end
567569
=#
568-
MOI.free!(m::MockLinQuadOptimizer) = nothing
570+
MOI.free!(m::MockLinQuadOptimizer) = nothing

src/solver_interface.jl

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -143,33 +143,29 @@ function get_number_linear_constraints end
143143
@deprecate lqs_getnumrows get_number_linear_constraints
144144

145145
"""
146-
add_linear_constraints!(m, rows::Vector{Int}, cols::Vector{Int},
147-
coefs::Vector{Float64},
146+
add_linear_constraints!(m, A::CSRMatrix{Float64},
148147
sense::Vector{Cchar}, rhs::Vector{Float64})::Void
149148
150149
Adds linear constraints of the form `Ax (sense) rhs` to the model `m`.
151150
152-
The A matrix is given in triplet form `A[rows[i], cols[i]] = coef[i]` for all
153-
`i`, and `length(rows) == length(cols) == length(coefs)`.
154-
151+
`sense` and `rhs` contain one element for each row in `A`.
155152
The `sense` is given by `backend_type(m, set)`.
156153
157154
Ranged constraints (`set=MOI.Interval`) should be added via `add_ranged_constraint!`
158155
instead.
156+
157+
See also: `LinQuadOptInterface.CSRMatrix`.
159158
"""
160159
function add_linear_constraints! end
161160
@deprecate lqs_addrows! add_linear_constraints!
162161

163162
"""
164-
add_ranged_constraints!(m, rows::Vector{Int}, cols::Vector{Int},
165-
coefs::Vector{Float64}, lowerbound::Vector{Float64}, upperbound::Vector{Float64})
163+
add_ranged_constraints!(m, A::CSRMatrix{Float64},
164+
lowerbound::Vector{Float64}, upperbound::Vector{Float64})
166165
167166
Adds linear constraints of the form `lowerbound <= Ax <= upperbound` to the
168167
model `m`.
169168
170-
The A matrix is given in triplet form `A[rows[i], cols[i]] = coef[i]` for all
171-
`i`,
172-
173169
This is a special case compared to standard `add_linear_constraints!` since it
174170
is often implemented via multiple API calls.
175171
"""

0 commit comments

Comments
 (0)