├── test ├── REQUIRE ├── .gitignore └── runtests.jl ├── REQUIRE ├── README.md ├── LICENSE └── src └── MathOptInterfaceGurobi.jl /test/REQUIRE: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/.gitignore: -------------------------------------------------------------------------------- 1 | *.lp 2 | -------------------------------------------------------------------------------- /REQUIRE: -------------------------------------------------------------------------------- 1 | julia 0.6 2 | Gurobi 3 | LinQuadOptInterface 4 | MathOptInterface 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MathOptInterfaceGurobi.jl 2 | 3 | **NOTE: This repo is discontinued. The code is being [merged into Gurobi.jl](https://github.com/JuliaOpt/Gurobi.jl/pull/125)** 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Joaquim Dias Garcia and contributors 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /test/runtests.jl: -------------------------------------------------------------------------------- 1 | using Gurobi, Base.Test, MathOptInterface, MathOptInterface.Test, MathOptInterfaceGurobi 2 | 3 | const MOIT = MathOptInterface.Test 4 | const MOIGRB = MathOptInterfaceGurobi 5 | 6 | @testset "MathOptInterfaceGurobi" begin 7 | @testset "Linear tests" begin 8 | linconfig = linconfig = MOIT.TestConfig() 9 | solver = GurobiOptimizer(OutputFlag=0) 10 | MOIT.contlineartest(solver, linconfig, ["linear10","linear12","linear8a","linear8b","linear8c"]) 11 | 12 | solver_nopresolve = GurobiOptimizer(OutputFlag=0, InfUnbdInfo=1) 13 | MOIT.contlineartest(solver_nopresolve, linconfig, ["linear10","linear12","linear8a"]) 14 | 15 | linconfig_nocertificate = MOIT.TestConfig(infeas_certificates=false) 16 | MOIT.linear12test(solver, linconfig_nocertificate) 17 | MOIT.linear8atest(solver, linconfig_nocertificate) 18 | 19 | # 10 is ranged 20 | end 21 | 22 | @testset "Quadratic tests" begin 23 | quadconfig = MOIT.TestConfig(atol=1e-4, rtol=1e-4, duals=false, query=false) 24 | solver = GurobiOptimizer(OutputFlag=0) 25 | MOIT.contquadratictest(solver, quadconfig) 26 | end 27 | 28 | @testset "Linear Conic tests" begin 29 | linconfig = MOIT.TestConfig() 30 | solver = GurobiOptimizer(OutputFlag=0) 31 | MOIT.lintest(solver, linconfig, ["lin3","lin4"]) 32 | 33 | solver_nopresolve = GurobiOptimizer(OutputFlag=0, InfUnbdInfo=1) 34 | MOIT.lintest(solver_nopresolve, linconfig) 35 | end 36 | 37 | @testset "Integer Linear tests" begin 38 | intconfig = MOIT.TestConfig() 39 | solver = GurobiOptimizer(OutputFlag=0) 40 | MOIT.intlineartest(solver, intconfig, ["int3"]) 41 | 42 | # 3 is ranged 43 | end 44 | @testset "ModelLike tests" begin 45 | intconfig = MOIT.TestConfig() 46 | solver = GurobiOptimizer() 47 | MOIT.validtest(solver) 48 | MOIT.emptytest(solver) 49 | solver2 = GurobiOptimizer() 50 | MOIT.copytest(solver,solver2) 51 | end 52 | end 53 | ; 54 | -------------------------------------------------------------------------------- /src/MathOptInterfaceGurobi.jl: -------------------------------------------------------------------------------- 1 | __precompile__() 2 | module MathOptInterfaceGurobi 3 | 4 | export GurobiOptimizer 5 | 6 | using Gurobi 7 | const GRB = Gurobi 8 | using MathOptInterface 9 | const MOI = MathOptInterface 10 | using LinQuadOptInterface 11 | const LQOI = LinQuadOptInterface 12 | 13 | const SUPPORTED_OBJECTIVES = [ 14 | LQOI.Linear, 15 | LQOI.Quad 16 | ] 17 | const SUPPORTED_CONSTRAINTS = [ 18 | (LQOI.Linear, LQOI.EQ), 19 | (LQOI.Linear, LQOI.LE), 20 | (LQOI.Linear, LQOI.GE), 21 | # (Linear, IV), 22 | (LQOI.Quad, LQOI.EQ), 23 | (LQOI.Quad, LQOI.LE), 24 | (LQOI.Quad, LQOI.GE), 25 | (LQOI.SinVar, LQOI.EQ), 26 | (LQOI.SinVar, LQOI.LE), 27 | (LQOI.SinVar, LQOI.GE), 28 | (LQOI.SinVar, LQOI.IV), 29 | (LQOI.SinVar, MOI.ZeroOne), 30 | (LQOI.SinVar, MOI.Integer), 31 | (LQOI.VecVar, LQOI.SOS1), 32 | (LQOI.VecVar, LQOI.SOS2), 33 | (LQOI.VecVar, MOI.Nonnegatives), 34 | (LQOI.VecVar, MOI.Nonpositives), 35 | (LQOI.VecVar, MOI.Zeros), 36 | (LQOI.VecLin, MOI.Nonnegatives), 37 | (LQOI.VecLin, MOI.Nonpositives), 38 | (LQOI.VecLin, MOI.Zeros) 39 | ] 40 | 41 | mutable struct GurobiOptimizer <: LQOI.LinQuadOptimizer 42 | LQOI.@LinQuadOptimizerBase 43 | env 44 | params::Dict{String,Any} 45 | GurobiOptimizer(::Void) = new() 46 | end 47 | 48 | LQOI.LinQuadModel(::Type{GurobiOptimizer},env) = GRB.Model(env::GRB.Env,"defaultname") 49 | 50 | function GurobiOptimizer(;kwargs...) 51 | 52 | env = GRB.Env() 53 | m = GurobiOptimizer(nothing) 54 | m.env = env 55 | m.params = Dict{String,Any}() 56 | MOI.empty!(m) 57 | for (name,value) in kwargs 58 | m.params[string(name)] = value 59 | GRB.setparam!(m.inner, string(name), value) 60 | end 61 | return m 62 | end 63 | 64 | function MOI.empty!(m::GurobiOptimizer) 65 | MOI.empty!(m,m.env) 66 | for (name,value) in m.params 67 | GRB.setparam!(m.inner, name, value) 68 | end 69 | end 70 | 71 | LQOI.lqs_supported_constraints(s::GurobiOptimizer) = SUPPORTED_CONSTRAINTS 72 | LQOI.lqs_supported_objectives(s::GurobiOptimizer) = SUPPORTED_OBJECTIVES 73 | #= 74 | inner wrapper 75 | =# 76 | 77 | #= 78 | Main 79 | =# 80 | 81 | # LinQuadSolver # Abstract type 82 | # done above 83 | 84 | # LQOI.lqs_setparam!(env, name, val) 85 | # TODO fix this one 86 | LQOI.lqs_setparam!(m::GurobiOptimizer, name, val) = GRB.setparam!(m.inner, string(name), val) 87 | 88 | # LQOI.lqs_setlogfile!(env, path) 89 | # TODO fix this one 90 | LQOI.lqs_setlogfile!(m::GurobiOptimizer, path) = GRB.setlogfile(m.env, path::String) 91 | 92 | # LQOI.lqs_getprobtype(m) 93 | # TODO - consider removing, apparently useless 94 | 95 | #= 96 | Constraints 97 | =# 98 | 99 | cintvec(v::Vector) = convert(Vector{Int32}, v) 100 | 101 | _getsense(m::GurobiOptimizer, ::MOI.EqualTo{Float64}) = Cchar('=') 102 | _getsense(m::GurobiOptimizer, ::MOI.LessThan{Float64}) = Cchar('<') 103 | _getsense(m::GurobiOptimizer, ::MOI.GreaterThan{Float64}) = Cchar('>') 104 | _getsense(m::GurobiOptimizer, ::MOI.Zeros) = Cchar('=') 105 | _getsense(m::GurobiOptimizer, ::MOI.Nonpositives) = Cchar('<') 106 | _getsense(m::GurobiOptimizer, ::MOI.Nonnegatives) = Cchar('>') 107 | _getboundsense(m::GurobiOptimizer, ::MOI.Nonpositives) = Cchar('>') 108 | _getboundsense(m::GurobiOptimizer, ::MOI.Nonnegatives) = Cchar('<') 109 | 110 | # LQOI.lqs_chgbds!(m, colvec, valvec, sensevec) 111 | # TODO - improve single type 112 | function LQOI.lqs_chgbds!(instance::GurobiOptimizer, colvec, valvec, sensevec) 113 | lb_len = count(x->x==Cchar('L'), sensevec) 114 | LB_val = Array{Float64}(0) 115 | sizehint!(LB_val, lb_len) 116 | LB_col = Array{Cint}(0) 117 | sizehint!(LB_col, lb_len) 118 | 119 | ub_len = count(x->x==Cchar('U'), sensevec) 120 | UB_val = Array{Float64}(0) 121 | sizehint!(UB_val, ub_len) 122 | UB_col = Array{Cint}(0) 123 | sizehint!(UB_col, ub_len) 124 | 125 | for i in eachindex(valvec) 126 | if sensevec[i] == Cchar('L') 127 | push!(LB_col, colvec[i]) 128 | push!(LB_val, valvec[i]) 129 | elseif sensevec[i] == Cchar('U') 130 | push!(UB_col, colvec[i]) 131 | push!(UB_val, valvec[i]) 132 | end 133 | end 134 | 135 | if lb_len > 0 136 | GRB.set_dblattrlist!(instance.inner, "LB", LB_col, LB_val) 137 | end 138 | 139 | if ub_len > 0 140 | GRB.set_dblattrlist!(instance.inner, "UB", UB_col, UB_val) 141 | end 142 | 143 | GRB.update_model!(instance.inner) 144 | nothing 145 | end 146 | 147 | 148 | # LQOI.lqs_getlb(m, col) 149 | LQOI.lqs_getlb(instance::GurobiOptimizer, col) = (GRB.update_model!(instance.inner);GRB.get_dblattrlist( instance.inner, "LB", GRB.ivec(col))[1]) 150 | # LQOI.lqs_getub(m, col) 151 | LQOI.lqs_getub(instance::GurobiOptimizer, col) = GRB.get_dblattrlist( instance.inner, "UB", GRB.ivec(col))[1] 152 | 153 | # LQOI.lqs_getnumrows(m) 154 | LQOI.lqs_getnumrows(instance::GurobiOptimizer) = GRB.num_constrs(instance.inner) 155 | 156 | # LQOI.lqs_addrows!(m, rowvec, colvec, coefvec, sensevec, rhsvec) 157 | LQOI.lqs_addrows!(instance::GurobiOptimizer, rowvec, colvec, coefvec, sensevec, rhsvec) = (GRB.add_constrs!(instance.inner, rowvec, colvec, coefvec, sensevec, rhsvec);GRB.update_model!(instance.inner)) 158 | 159 | # LQOI.lqs_getrhs(m, rowvec) 160 | LQOI.lqs_getrhs(instance::GurobiOptimizer, row) = GRB.get_dblattrlist( instance.inner, "RHS", GRB.ivec(row))[1] 161 | 162 | # colvec, coef = LQOI.lqs_getrows(m, rowvec) 163 | # TODO improve 164 | function LQOI.lqs_getrows(instance::GurobiOptimizer, idx) 165 | A = GRB.get_constrs(instance.inner, idx, 1)' 166 | return A.rowval-1, A.nzval 167 | end 168 | 169 | # LQOI.lqs_getcoef(m, row, col) #?? 170 | # TODO improve 171 | function LQOI.lqs_getcoef(instance::GurobiOptimizer, row, col) #?? 172 | return getcoeff(model::Model, row::Integer, col::Integer) 173 | # A = GRB.get_rows(m, row, row)' 174 | # cols = A.rowval 175 | # vals = A.nzval 176 | 177 | # pos = findfirst(cols, col) 178 | # if pos > 0 179 | # return vals[pos] 180 | # else 181 | # return 0.0 182 | # end 183 | end 184 | 185 | # LQOI.lqs_chgcoef!(m, row, col, coef) 186 | # TODO SPLIT THIS ONE 187 | function LQOI.lqs_chgcoef!(instance::GurobiOptimizer, row, col, coef) 188 | if row == 0 189 | GRB.set_dblattrlist!(instance.inner, "Obj", Cint[col], Float64[coef]) 190 | elseif col == 0 191 | GRB.set_dblattrlist!(instance.inner, "RHS", Cint[row], Float64[coef]) 192 | else 193 | GRB.chg_coeffs!(instance.inner, row, col, coef) 194 | #TODO fix this function in gurobi 195 | end 196 | end 197 | 198 | # LQOI.lqs_delrows!(m, row, row) 199 | LQOI.lqs_delrows!(instance::GurobiOptimizer, rowbeg, rowend) = GRB.del_constrs!(instance.inner, cintvec(collect(rowbeg:rowend))) 200 | 201 | # LQOI.lqs_chgctype!(m, colvec, typevec) 202 | # TODO fix types 203 | LQOI.lqs_chgctype!(instance::GurobiOptimizer, colvec, typevec) = GRB.set_charattrlist!(instance.inner, "VType", GRB.ivec(colvec), GRB.cvec(typevec)) 204 | 205 | # LQOI.lqs_chgsense!(m, rowvec, sensevec) 206 | # TODO fix types 207 | LQOI.lqs_chgsense!(instance::GurobiOptimizer, rowvec, sensevec) = GRB.set_charattrlist!(instance.inner, "Sense", GRB.ivec(rowvec), GRB.cvec(sensevec)) 208 | 209 | const VAR_TYPE_MAP = Dict{Symbol,Cchar}( 210 | :CONTINUOUS => Cchar('C'), 211 | :INTEGER => Cchar('I'), 212 | :BINARY => Cchar('B') 213 | ) 214 | LQOI.lqs_vartype_map(m::GurobiOptimizer) = VAR_TYPE_MAP 215 | 216 | # LQOI.lqs_addsos(m, colvec, valvec, typ) 217 | LQOI.lqs_addsos!(instance::GurobiOptimizer, colvec, valvec, typ) = (GRB.add_sos!(instance.inner, typ, colvec, valvec);GRB.update_model!(instance.inner)) 218 | # LQOI.lqs_delsos(m, idx, idx) 219 | LQOI.lqs_delsos!(instance::GurobiOptimizer, idx1, idx2) = (GRB.del_sos!(instance.inner, cintvec(collect(idx1:idx2)));GRB.update_model!(instance.inner)) 220 | 221 | const SOS_TYPE_MAP = Dict{Symbol,Symbol}( 222 | :SOS1 => :SOS1,#Cchar('1'), 223 | :SOS2 => :SOS2#Cchar('2') 224 | ) 225 | LQOI.lqs_sertype_map(m::GurobiOptimizer) = SOS_TYPE_MAP 226 | 227 | # LQOI.lqs_getsos(m, idx) 228 | # TODO improve getting processes 229 | function LQOI.lqs_getsos(instance::GurobiOptimizer, idx) 230 | A, types = GRB.get_sos_matrix(instance.inner) 231 | line = A[idx,:] #sparse vec 232 | cols = line.nzind 233 | vals = line.nzval 234 | typ = types[idx] == Cint(1) ? :SOS1 : :SOS2 235 | return cols, vals, typ 236 | end 237 | 238 | # LQOI.lqs_getnumqconstrs(m) 239 | LQOI.lqs_getnumqconstrs(instance::GurobiOptimizer) = GRB.num_qconstrs(instance.inner) 240 | 241 | # LQOI.lqs_addqconstr(m, cols,coefs,rhs,sense, I,J,V) 242 | LQOI.lqs_addqconstr!(instance::GurobiOptimizer, cols,coefs,rhs,sense, I,J,V) = GRB.add_qconstr!(instance.inner, cols, coefs, I, J, V, sense, rhs) 243 | 244 | # LQOI.lqs_chgrngval 245 | LQOI.lqs_chgrngval!(instance::GurobiOptimizer, rows, vals) = GRB.chg_rhsrange!(instance.inner, cintvec(rows), -vals) 246 | 247 | const CTR_TYPE_MAP = Dict{Symbol,Cchar}( 248 | :RANGE => Cchar('R'), 249 | :LOWER => Cchar('L'), 250 | :UPPER => Cchar('U'), 251 | :EQUALITY => Cchar('E') 252 | ) 253 | LQOI.lqs_ctrtype_map(m::GurobiOptimizer) = CTR_TYPE_MAP 254 | 255 | #= 256 | Objective 257 | =# 258 | 259 | # LQOI.lqs_copyquad(m, intvec,intvec, floatvec) #? 260 | function LQOI.lqs_copyquad!(instance::GurobiOptimizer, I, J, V) 261 | GRB.delq!(instance.inner) 262 | for i in eachindex(V) 263 | if I[i] == J[i] 264 | V[i] /= 2 265 | end 266 | end 267 | GRB.add_qpterms!(instance.inner, I, J, V) 268 | return nothing 269 | end 270 | 271 | # LQOI.lqs_chgobj(m, colvec,coefvec) 272 | function LQOI.lqs_chgobj!(instance::GurobiOptimizer, colvec, coefvec) 273 | nvars = GRB.num_vars(instance.inner) 274 | obj = zeros(Float64, nvars) 275 | 276 | for i in eachindex(colvec) 277 | obj[colvec[i]] = coefvec[i] 278 | end 279 | 280 | GRB.set_dblattrarray!(instance.inner, "Obj", 1, num_vars(instance.inner), obj) 281 | GRB.update_model!(instance.inner) 282 | nothing 283 | end 284 | 285 | # LQOI.lqs_chgobjsen(m, symbol) 286 | # TODO improve min max names 287 | function LQOI.lqs_chgobjsen!(instance::GurobiOptimizer, symbol) 288 | if symbol in [:minimize, :Min] 289 | GRB.set_sense!(instance.inner, :minimize) 290 | else 291 | GRB.set_sense!(instance.inner, :maximize) 292 | end 293 | GRB.update_model!(instance.inner) 294 | end 295 | 296 | 297 | # LQOI.lqs_getobj(instance.inner) 298 | LQOI.lqs_getobj(instance::GurobiOptimizer) = GRB.get_dblattrarray( instance.inner, "Obj", 1, num_vars(instance.inner) ) 299 | 300 | # lqs_getobjsen(m) 301 | function LQOI.lqs_getobjsen(instance::GurobiOptimizer) 302 | s = GRB.model_sense(instance.inner) 303 | if s in [:maximize, :Max] 304 | return MOI.MaxSense 305 | else 306 | return MOI.MinSense 307 | end 308 | end 309 | 310 | #= 311 | Variables 312 | =# 313 | 314 | # LQOI.lqs_getnumcols(m) 315 | LQOI.lqs_getnumcols(instance::GurobiOptimizer) = (GRB.update_model!(instance.inner); GRB.num_vars(instance.inner)) 316 | 317 | # LQOI.lqs_newcols!(m, int) 318 | LQOI.lqs_newcols!(instance::GurobiOptimizer, int) = (GRB.add_cvars!(instance.inner, zeros(int));GRB.update_model!(instance.inner)) 319 | 320 | # LQOI.lqs_delcols!(m, col, col) 321 | LQOI.lqs_delcols!(instance::GurobiOptimizer, col, col2) = (GRB.del_vars!(instance.inner, col);GRB.update_model!(instance.inner)) 322 | 323 | # LQOI.lqs_addmipstarts(m, colvec, valvec) 324 | function LQOI.lqs_addmipstarts!(instance::GurobiOptimizer, colvec, valvec) 325 | x = zeros(GRB.num_vars(instance.inner)) 326 | for i in eachindex(colvec) 327 | x[colvec[i]] = valvec[i] 328 | end 329 | GRB.loadbasis(instance.inner, x) 330 | end 331 | #= 332 | Solve 333 | =# 334 | 335 | # LQOI.lqs_mipopt!(m) 336 | LQOI.lqs_mipopt!(instance::GurobiOptimizer) = LQOI.lqs_lpopt!(instance) 337 | 338 | # LQOI.lqs_qpopt!(m) 339 | LQOI.lqs_qpopt!(instance::GurobiOptimizer) = LQOI.lqs_lpopt!(instance) 340 | 341 | # LQOI.lqs_lpopt!(m) 342 | LQOI.lqs_lpopt!(instance::GurobiOptimizer) = (GRB.update_model!(instance.inner);GRB.optimize(instance.inner)) 343 | 344 | # LQOI.lqs_terminationstatus(m) 345 | function LQOI.lqs_terminationstatus(instance::GurobiOptimizer) 346 | 347 | stat = get_status(instance.inner) 348 | 349 | if stat == :loaded 350 | return MOI.OtherError 351 | elseif stat == :optimal 352 | return MOI.Success 353 | elseif stat == :infeasible 354 | if hasdualray(instance) 355 | return MOI.Success 356 | else 357 | return MOI.InfeasibleNoResult 358 | end 359 | elseif stat == :inf_or_unbd 360 | return MOI.InfeasibleOrUnbounded 361 | elseif stat == :unbounded 362 | if hasprimalray(instance) 363 | return MOI.Success 364 | else 365 | return MOI.UnboundedNoResult 366 | end 367 | elseif stat == :cutoff 368 | return MOI.ObjectiveLimit 369 | elseif stat == :iteration_limit 370 | return MOI.IterationLimit 371 | elseif stat == :node_limit 372 | return MOI.NodeLimit 373 | elseif stat == :time_limit 374 | return MOI.TimeLimit 375 | elseif stat == :solution_limit 376 | return MOI.SolutionLimit 377 | elseif stat == :interrupted 378 | return MOI.Interrupted 379 | elseif stat == :numeric 380 | return MOI.NumericalError 381 | elseif stat == :suboptimal 382 | return MOI.OtherLimit 383 | elseif stat == :inprogress 384 | return MOI.OtherError 385 | elseif stat == :user_obj_limit 386 | return MOI.ObjectiveLimit 387 | end 388 | return MOI.OtherError 389 | end 390 | 391 | 392 | function LQOI.lqs_primalstatus(instance::GurobiOptimizer) 393 | 394 | stat = get_status(instance.inner) 395 | 396 | if stat == :optimal 397 | return MOI.FeasiblePoint 398 | elseif stat == :solution_limit 399 | return MOI.FeasiblePoint 400 | elseif stat in [:inf_or_unbd, :unbounded] && hasprimalray(instance) 401 | return MOI.InfeasibilityCertificate 402 | elseif stat == :suboptimal 403 | return MOI.FeasiblePoint 404 | else 405 | return MOI.UnknownResultStatus 406 | end 407 | end 408 | function LQOI.lqs_dualstatus(instance::GurobiOptimizer) 409 | stat = get_status(instance.inner) 410 | 411 | if GRB.is_mip(instance.inner) || GRB.is_qcp(instance.inner) 412 | return MOI.UnknownResultStatus 413 | else 414 | if stat == :optimal 415 | return MOI.FeasiblePoint 416 | elseif stat == :solution_limit 417 | return MOI.FeasiblePoint 418 | elseif stat in [:inf_or_unbd, :infeasible] && hasdualray(instance) 419 | return MOI.InfeasibilityCertificate 420 | elseif stat == :suboptimal 421 | return MOI.FeasiblePoint 422 | else 423 | return MOI.UnknownResultStatus 424 | end 425 | end 426 | end 427 | 428 | 429 | # LQOI.lqs_getx!(m, place) 430 | LQOI.lqs_getx!(instance::GurobiOptimizer, place) = GRB.get_dblattrarray!(place, instance.inner, "X", 1) 431 | 432 | # LQOI.lqs_getax!(m, place) 433 | function LQOI.lqs_getax!(instance::GurobiOptimizer, place) 434 | GRB.get_dblattrarray!(place, instance.inner, "Slack", 1) 435 | rhs = GRB.get_dblattrarray(instance.inner, "RHS", 1, num_constrs(instance.inner)) 436 | for i in eachindex(place) 437 | place[i] = -place[i]+rhs[i] 438 | end 439 | nothing 440 | end 441 | # LQOI.lqs_getdj!(m, place) 442 | LQOI.lqs_getdj!(instance::GurobiOptimizer, place) = GRB.get_dblattrarray!(place, instance.inner, "RC", 1) 443 | 444 | # LQOI.lqs_getpi!(m, place) 445 | LQOI.lqs_getpi!(instance::GurobiOptimizer, place) = GRB.get_dblattrarray!(place, instance.inner, "Pi", 1) 446 | 447 | # LQOI.lqs_getobjval(m) 448 | LQOI.lqs_getobjval(instance::GurobiOptimizer) = GRB.get_objval(instance.inner) 449 | 450 | # LQOI.lqs_getbestobjval(m) 451 | LQOI.lqs_getbestobjval(instance::GurobiOptimizer) = GRB.get_objval(instance.inner) 452 | 453 | # LQOI.lqs_getmiprelgap(m) 454 | function LQOI.lqs_getmiprelgap(instance::GurobiOptimizer) 455 | L = GRB.get_objval(instance.inner) 456 | U = GRB.get_objbound(instance.inner) 457 | return abs(U-L)/U 458 | end 459 | 460 | # LQOI.lqs_getitcnt(m) 461 | LQOI.lqs_getitcnt(instance::GurobiOptimizer) = GRB.get_iter_count(instance.inner) 462 | 463 | # LQOI.lqs_getbaritcnt(m) 464 | LQOI.lqs_getbaritcnt(instance::GurobiOptimizer) = GRB.get_barrier_iter_count(instance.inner) 465 | 466 | # LQOI.lqs_getnodecnt(m) 467 | LQOI.lqs_getnodecnt(instance::GurobiOptimizer) = GRB.get_node_count(instance.inner) 468 | 469 | # LQOI.lqs_dualfarkas(m, place) 470 | LQOI.lqs_dualfarkas!(instance::GurobiOptimizer, place) = GRB.get_dblattrarray!(place, instance.inner, "FarkasDual", 1) 471 | 472 | function hasdualray(instance::GurobiOptimizer) 473 | try 474 | GRB.get_dblattrarray(instance.inner, "FarkasDual", 1, GRB.num_constrs(instance.inner)) 475 | return true 476 | catch 477 | return false 478 | end 479 | end 480 | 481 | # LQOI.lqs_getray(m, place) 482 | LQOI.lqs_getray!(instance::GurobiOptimizer, place) = GRB.get_dblattrarray!(place, instance.inner, "UnbdRay", 1) 483 | 484 | function hasprimalray(instance::GurobiOptimizer) 485 | try 486 | GRB.get_dblattrarray(instance.inner, "UnbdRay", 1, GRB.num_vars(instance.inner)) 487 | return true 488 | catch 489 | return false 490 | end 491 | end 492 | 493 | MOI.free!(m::GurobiOptimizer) = GRB.free_model(m.inner) 494 | 495 | """ 496 | writeproblem(m: :MOI.AbstractOptimizer, filename::String) 497 | Writes the current problem data to the given file. 498 | Supported file types are solver-dependent. 499 | """ 500 | writeproblem(m::GurobiOptimizer, filename::String, flags::String="") = GRB.write_model(m.inner, filename) 501 | 502 | 503 | # blocked 504 | MOI.addconstraint!(m::GurobiOptimizer, func::LQOI.Linear, set::LQOI.IV) = error("not supported") 505 | MOI.addconstraints!(m::GurobiOptimizer, func::Vector{LQOI.Linear}, set::Vector{LQOI.IV}) = error("not supported") 506 | 507 | MOI.canget(m::GurobiOptimizer, any, c::LQOI.LCI{LQOI.IV}) = false 508 | MOI.canmodifyconstraint(m::GurobiOptimizer, c::LQOI.LCI{LQOI.IV}, chg) = false 509 | MOI.candelete(m::GurobiOptimizer, c::LQOI.LCI{LQOI.IV}) = false 510 | 511 | end # module --------------------------------------------------------------------------------