Skip to content

Commit

Permalink
initial implementation of new default solvers; passing on Julia 0.6
Browse files Browse the repository at this point in the history
  • Loading branch information
mlubin committed Feb 6, 2017
1 parent 9bef25f commit 40c8eea
Show file tree
Hide file tree
Showing 7 changed files with 163 additions and 29 deletions.
2 changes: 1 addition & 1 deletion REQUIRE
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
julia 0.5
MathProgBase 0.5.1 0.6
MathProgBase 0.6 0.7
ReverseDiffSparse 0.7 0.8
ForwardDiff 0.3 0.4
Calculus
10 changes: 5 additions & 5 deletions src/JuMPArray.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.

immutable JuMPArray{T,N,NT<:NTuple} <: JuMPContainer{T,N}
immutable JuMPArray{T,N,NT} <: JuMPContainer{T,N}
innerArray::Array{T,N}
indexsets::NT
lookup::NTuple{N,Dict}
lookup::NTuple{N,Any}
meta::Dict{Symbol,Any}
end

@generated function JuMPArray{T,N}(innerArray::Array{T,N}, indexsets::NTuple{N})
@generated function JuMPArray{T,N}(innerArray::Array{T,N}, indexsets::NTuple{N,Any})
dicttuple = Expr(:tuple)
for i in 1:N
inner = quote
Expand All @@ -36,14 +36,14 @@ end

Base.getindex(d::JuMPArray, ::Colon) = d.innerArray[:]

@generated function Base.getindex{T,N,NT<:NTuple}(d::JuMPArray{T,N,NT}, idx...)
@generated function Base.getindex{T,N,NT}(d::JuMPArray{T,N,NT}, idx...)
if N != length(idx)
error("Indexed into a JuMPArray with $(length(idx)) indices (expected $N indices)")
end
Expr(:call, :getindex, :(d.innerArray), _to_cartesian(d,NT,idx)...)
end

@generated function Base.setindex!{T,N,NT<:NTuple}(d::JuMPArray{T,N,NT}, v, idx...)
@generated function Base.setindex!{T,N,NT}(d::JuMPArray{T,N,NT}, v, idx...)
if N != length(idx)
error("Indexed into a JuMPArray with $(length(idx)) indices (expected $N indices)")
end
Expand Down
96 changes: 90 additions & 6 deletions src/solvers.jl
Original file line number Diff line number Diff line change
Expand Up @@ -37,19 +37,103 @@ function ProblemTraits(m::Model; relaxation=false)
sos = !isempty(m.sosconstr)
ProblemTraits(int, !(qp|qc|nlp|soc|sdp|sos), qp, qc, nlp, soc, sdp, sos, soc|sdp)
end

# these are the default solver packages in order of decreasing precedence
# for each supported problem class.

const LPsolvers = [(:Clp,:ClpSolver),
(:GLPKMathProgInterface,:GLPKSolverLP),
(:Gurobi,:GurobiSolver),
(:CPLEX,:CplexSolver),
(:Mosek,:MosekSolver),
(:Xpress,:XpressSolver)]

const MIPsolvers = [(:Cbc,:CbcSolver),
(:GLPKMathProgInterface,:GLPKSolverMIP),
(:Gurobi,:GurobiSolver),
(:CPLEX,:CplexSolver),
(:Mosek,:MosekSolver),
(:Xpress,:XpressSolver)]

const QPsolvers = [(:Gurobi,:GurobiSolver),
(:CPLEX,:CplexSolver),
(:Mosek,:MosekSolver),
(:Ipopt,:IpoptSolver),
(:Xpress,:XpressSolver)]

const SDPsolvers = [(:Mosek,:MosekSolver),
(:SCS,:SCSSolver)]

const NLPsolvers = [(:Ipopt,:IpoptSolver),
(:KNITRO,:KnitroSolver),
(:Mosek,:MosekSolver)]

const Conicsolvers = [(:ECOS,:ECOSSolver),
(:SCS,:SCSSolver),
(:Mosek,:MosekSolver)]

function loaddefaultsolvers()
for solverlist in [LPsolvers,MIPsolvers,QPsolvers,SDPsolvers,NLPsolvers,Conicsolvers]
for (pkgname,solvername) in solverlist
try
eval(Expr(:import,pkgname))
# stop when we've found a working solver in this category
continue
end
end
end
end

using Base.Meta

for solvertype in ["LP", "MIP", "QP", "SDP", "NLP", "Conic"]
solvers = Symbol(solvertype*"solvers")
functionname = Symbol("default"*solvertype*"solver")
if VERSION > v"0.6.0-"
@eval function ($functionname)()
for (pkgname,solvername) in $solvers
if isdefined(Main,pkgname)
return getfield(getfield(Main,pkgname),solvername)()
end
end
solvers = [String(p) for (p,s) in $solvers]
error("No ", $solvertype, " solver detected. The recognized solver packages are: ", solvers,". One of these solvers must be installed and explicitly loaded with a \"using\" statement.")
end
else
@eval function ($functionname)()
for (pkgname,solvername) in $solvers
alreadydefined = isdefined(Main,pkgname)
if !alreadydefined
try
eval(Expr(:import,pkgname))
# if we got here, package works but wasn't loaded,
# print warning.
Base.warn_once(string("The default ", $solvertype, " package is installed but not loaded. In Julia 0.6 and later, an explicit \"using ", pkgname, "\" statement will be required in order for the solver to be detected and used as a default."))
catch
continue
end
end
return getfield(getfield(Main,pkgname),solvername)()
end
suggestions = join(["\"$(pkgname)\", " for (pkgname,solvername) in $solvers], ' ')
error("No ",$solvertype, " solver detected. Try installing one of the following packages: ", suggestions, " and restarting Julia")
end
end
end

function default_solver(traits::ProblemTraits)
if traits.nlp
MathProgBase.defaultNLPsolver
defaultNLPsolver()
elseif traits.int || traits.sos
MathProgBase.defaultMIPsolver
defaultMIPsolver()
elseif traits.sdp
MathProgBase.defaultSDPsolver
defaultSDPsolver()
elseif traits.conic
MathProgBase.defaultConicsolver
defaultConicsolver()
elseif traits.qp || traits.qc
MathProgBase.defaultQPsolver
defaultQPsolver()
else
MathProgBase.defaultLPsolver
defaultLPsolver()
end
end

Expand Down
18 changes: 15 additions & 3 deletions test/model.jl
Original file line number Diff line number Diff line change
Expand Up @@ -550,7 +550,11 @@ end
@variable(mod, 0 <= x <= 1)
@variable(mod, 0 <= y <= 1)
obj = [5,1]'*[x,y]
@objective(mod, Max, obj[1])
if VERSION < v"0.6.0-dev"
@objective(mod, Max, obj[1])
else
@objective(mod, Max, obj)
end
A = [1 1
2 1]
@constraint(mod, A*[x,y] .<= [6,7])
Expand Down Expand Up @@ -698,7 +702,11 @@ end
@variable(modV, y[1:7])
@constraint(modV, A*x + B*y .<= 1)
obj = (x'*2A')*(2A*x) + (B*2y)'*(B*(2y))
@objective(modV, Max, obj[1])
if VERSION < v"0.6.0-dev"
@objective(modV, Max, obj[1])
else
@objective(modV, Max, obj)
end

modS = Model()
@variable(modS, x[1:10])
Expand Down Expand Up @@ -726,7 +734,11 @@ end
@variable(mod, 0 <= z[1:p] <= 1)
end
obj = (y-X*β)'*(y-X*β)
@objective(mod, Min, obj[1])
if VERSION < v"0.6.0-dev"
@objective(mod, Min, obj[1])
else
@objective(mod, Min, obj)
end
@constraint(mod, eye(p)*β .<= M*eye(p)*z)
@constraint(mod, eye(p)*β .>= -M*eye(p)*z)
@constraint(mod, sum(z) == K)
Expand Down
13 changes: 11 additions & 2 deletions test/operator.jl
Original file line number Diff line number Diff line change
Expand Up @@ -709,10 +709,19 @@ const sub2 = JuMP.repl[:sub2]
0 4 5
6 0 7]
B = sparse(A)
@constraint(m, x'*A*x .>= 1)
if VERSION < v"0.6.0-dev"
@constraint(m, x'*A*x .>= 1)
else
# force vector output
@constraint(m, reshape(x,(1,3))*A*x .>= 1)
end
@test vec_eq(m.quadconstr[1].terms, [x[1]*x[1] + 2x[1]*x[2] + 4x[2]*x[2] + 9x[1]*x[3] + 5x[2]*x[3] + 7x[3]*x[3] - 1])
@test m.quadconstr[1].sense == :(>=)
@constraint(m, x'*A*x .>= 1)
if VERSION < v"0.6.0-dev"
@constraint(m, x'*A*x .>= 1)
else
@constraint(m, x'*A*x >= 1)
end
@test vec_eq(m.quadconstr[1].terms, m.quadconstr[2].terms)

mat = [ 3x[1] + 12x[3] + 4x[2]
Expand Down
27 changes: 20 additions & 7 deletions test/print.jl
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,11 @@ end
io_test(REPLMode, rng2_1, "rng2_1[i,j] free $fa i $inset {1,2,$dots,9,10}, j $inset {a,b,c}")
io_test(REPLMode, tri_1, "tri_1[i,j] free $fa i $inset {1,2,3}, j $inset {$dots}")
io_test(REPLMode, tri_2, "tri_2[i,j] free $fa i $inset {1,2,3}, j $inset {$dots}")
io_test(REPLMode, tri_3, "tri_3[(i,j),k] free $fa (i,j) $inset {(1,3),(2,4),(3,5),(4,6),(5,7)}, k $inset {$dots}")
if VERSION < v"0.6.0-dev"
io_test(REPLMode, tri_3, "tri_3[(i,j),k] free $fa (i,j) $inset {(1,3),(2,4),(3,5),(4,6),(5,7)}, k $inset {$dots}")
else
io_test(REPLMode, tri_3, "tri_3[(i, j),k] free $fa (i, j) $inset {(1, 3),(2, 4),(3, 5),(4, 6),(5, 7)}, k $inset {$dots}")
end
io_test(REPLMode, iter_1, "iter_1[i] free $fa i $inset {a}")

io_test(IJuliaMode, rng_unit1, "rng_unit1_{i} free \\quad\\forall i \\in \\{1,2,\\dots,9,10\\}")
Expand All @@ -116,7 +120,11 @@ end
io_test(IJuliaMode, rng2_1, "rng2_1_{i,j} free \\quad\\forall i \\in \\{1,2,\\dots,9,10\\}, j \\in \\{a,b,c\\}")
io_test(IJuliaMode, tri_1, "tri_1_{i,j} free \\quad\\forall i \\in \\{1,2,3\\}, j \\in \\{\\dots\\}")
io_test(IJuliaMode, tri_2, "tri_2_{i,j} free \\quad\\forall i \\in \\{1,2,3\\}, j \\in \\{\\dots\\}")
io_test(IJuliaMode, tri_3, "tri_3_{(i,j),k} free \\quad\\forall (i,j) \\in \\{(1,3),(2,4),(3,5),(4,6),(5,7)\\}, k \\in \\{\\dots\\}")
if VERSION < v"0.6.0-dev"
io_test(IJuliaMode, tri_3, "tri_3_{(i,j),k} free \\quad\\forall (i,j) \\in \\{(1,3),(2,4),(3,5),(4,6),(5,7)\\}, k \\in \\{\\dots\\}")
else
io_test(IJuliaMode, tri_3, "tri_3_{(i, j),k} free \\quad\\forall (i, j) \\in \\{(1, 3),(2, 4),(3, 5),(4, 6),(5, 7)\\}, k \\in \\{\\dots\\}")
end
io_test(IJuliaMode, iter_1, "iter_1_{i} free \\quad\\forall i \\in \\{a\\}")
end

Expand Down Expand Up @@ -173,8 +181,8 @@ end
end



@testset "JuMPContainer{Number}" begin
# TEMPORARY: default solvers aren't working on 0.6 yet
if VERSION < v"0.6.0-dev"; @testset "JuMPContainer{Number}" begin
# The same output for REPL and IJulia, so only testing one
mod = Model()
@variable(mod, i*j <= w[i=9:10, [:Apple,5,:Banana], j=-1:+1] <= i*j)
Expand Down Expand Up @@ -301,7 +309,7 @@ end
[b,3] = 3.0
""")

end
end; end



Expand Down Expand Up @@ -587,8 +595,13 @@ end

v = [x,y,x]
A = [x y; y x]
io_test(REPLMode, v, "JuMP.Variable[x,y,x]")
io_test(IJuliaMode, v, "JuMP.Variable[x,y,x]")
if VERSION < v"0.6.0-dev"
io_test(REPLMode, v, "JuMP.Variable[x,y,x]")
io_test(IJuliaMode, v, "JuMP.Variable[x,y,x]")
else
io_test(REPLMode, v, "JuMP.Variable[x, y, x]")
io_test(IJuliaMode, v, "JuMP.Variable[x, y, x]")
end

io_test(REPLMode, A, "JuMP.Variable[x y; y x]")
io_test(IJuliaMode, A, "JuMP.Variable[x y; y x]")
Expand Down
26 changes: 21 additions & 5 deletions test/qcqpmodel.jl
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,11 @@ using Base.Test
modV = Model(solver=solver)
@variable(modV, 1.1*i <= x[i=1:3] <= 2.5*i, Int)
obj = x'*[10 1.5 0; 1.5 5 0; 0 0 9]*x
@objective(modV, Min, obj[1])
if VERSION < v"0.6.0-dev"
@objective(modV, Min, obj[1])
else
@objective(modV, Min, obj)
end
A = [ 0 1 -1.7
0.5 -1 0]
@constraint(modV, A*x .<= zeros(2))
Expand All @@ -54,7 +58,11 @@ using Base.Test
modV = Model(solver=solver)
@variable(modV, 1.1*i <= x[i=1:3] <= 2.5*i, Int)
obj = x'*sparse([10 1.5 0; 1.5 5 0; 0 0 9])*x
@objective(modV, Min, obj[1])
if VERSION < v"0.6.0-dev"
@objective(modV, Min, obj[1])
else
@objective(modV, Min, obj)
end
A = sparse([ 0 1 -1.7
0.5 -1 0])
@constraint(modV, A*x .<= zeros(2))
Expand All @@ -76,7 +84,11 @@ using Base.Test
@variable(modV, 1.1*i <= x[i=1:3] <= 2.5*i, Int)
Q = [10 3 0; 0 5 0; 0 0 9]
obj = x'Q*x
@objective(modV, Min, obj[1])
if VERSION < v"0.6.0-dev"
@objective(modV, Min, obj[1])
else
@objective(modV, Min, obj)
end
A = [ 0 -1 1.7
-0.5 1 0]
@constraint(modV, A*x .>= zeros(2))
Expand All @@ -100,8 +112,12 @@ using Base.Test
modV = Model(solver=solver)
@variable(modV, 0.5 <= x <= 2 )
@variable(modV, 0 <= y <= 30 )
obj = [x y]*ones(2,2)*[x,y]
@objective(modV, Min, obj[1])
obj = [x,y]'ones(2,2)*[x,y]
if VERSION < v"0.6.0-dev"
@objective(modV, Min, obj[1])
else
@objective(modV, Min, obj)
end
@constraint(modV, ones(1,2)*[x,y] .>= 1)
@test solve(modV) == :Optimal
@test isapprox(getobjectivevalue(modV), 1.0, atol=1e-6)
Expand Down

0 comments on commit 40c8eea

Please sign in to comment.