Skip to content

Commit

Permalink
Julia 0.7 (#100)
Browse files Browse the repository at this point in the history
* is_apple, is_unix were moved to Sys; Base.Libdl was moved out of Base

* Void -> Nothing, IntSet -> BitSet

* broadcasting +,= where necessary

* kwargs translate to NamedTuple

Model.options has become an iterator over pairs: (:kwrd=>val)

* fix deprecated constructors Array{T}(n), full(sparse)

* Base.@gc_preserve -> GC.@preserve

* importall is deprecated

import explicitly every function extended in MPBWrapper.jl

* dot is in LinearAlgebra; sparse in SparseArrays

* using Test, SCS globally in runtests

* Pkg is out of Base

* Add missing using: LinearAlgebra, SparseArrays, MathProgBase

* tidy test_problems

* fix: syntax for NamedTuple in setwarmstart!

* using Compat where necessary

* add VERSION-dependent addoption!(::SCSMathProgModel, option, value)

* add VERSION-dependent check for warmstarting

* remove superfluous @compat
  • Loading branch information
kalmarek authored and mlubin committed May 6, 2018
1 parent c377f2f commit b149b73
Show file tree
Hide file tree
Showing 13 changed files with 683 additions and 73 deletions.
10 changes: 7 additions & 3 deletions deps/build.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,17 @@ using BinDeps

@BinDeps.setup

blasvendor = Base.BLAS.vendor()
using Compat.Libdl
using Compat.LinearAlgebra.BLAS
using Compat.Sys: isapple

blasvendor = BLAS.vendor()

direct = library_dependency("libscsdir", aliases=["libscsdir64"])
indirect = library_dependency("libscsindir", aliases=["libscsindir64"])

# TODO: Provide both libs in the "scs" Homebrew package.
# if is_apple()
# if Sys.isapple()
# using Homebrew
# provides(Homebrew.HB, "scs", [direct, indirect], os = :Darwin)
# end
Expand All @@ -35,7 +39,7 @@ prefix = joinpath(BinDeps.depsdir(direct), "usr")
srcdir = joinpath(BinDeps.depsdir(direct), "src", "scs-$version/")

ldflags = ""
if is_apple()
if isapple()
ldflags = "$ldflags -undefined suppress -flat_namespace"
end
cflags = "-DCOPYAMATRIX -DDLONG -DUSE_LAPACK -DCTRLC=1"
Expand Down
14 changes: 7 additions & 7 deletions src/MOIWrapper.jl
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ end
mutable struct SCSOptimizer <: MOI.AbstractOptimizer
cone::ConeData
maxsense::Bool
data::Union{Void, ModelData} # only non-Void between MOI.copy! and MOI.optimize!
data::Union{Nothing, ModelData} # only non-Void between MOI.copy! and MOI.optimize!
sol::MOISolution
function SCSOptimizer()
new(ConeData(), false, nothing, MOISolution())
Expand Down Expand Up @@ -169,7 +169,7 @@ function _scalecoef(rows, coef, minus, ::Type{MOI.PositiveSemidefiniteConeTriang
scaling = minus ? -1 : 1
scaling2 = rev ? scaling / 2 : scaling * 2
output = copy(coef)
diagidx = IntSet()
diagidx = BitSet()
for i in 1:d
push!(diagidx, trimap(i, i))
end
Expand Down Expand Up @@ -232,11 +232,11 @@ function MOIU.loadconstraint!(optimizer::SCSOptimizer, ci, f::MOI.VectorAffineFu
offset = constroffset(optimizer, ci)
rows = constrrows(s)
optimizer.cone.nrows[offset] = length(rows)
i = offset + rows
i = offset .+ rows
# The SCS format is b - Ax ∈ cone
# so minus=false for b and minus=true for A
optimizer.data.b[i] = scalecoef(rows, orderval(f.constant, s), false, s)
append!(optimizer.data.I, offset + orderidx(I, s))
append!(optimizer.data.I, offset .+ orderidx(I, s))
append!(optimizer.data.J, J)
append!(optimizer.data.V, scalecoef(I, V, true, s))
end
Expand Down Expand Up @@ -268,7 +268,7 @@ MOIU.canload(::SCSOptimizer, ::MOI.ObjectiveSense) = true
function MOIU.load!(::SCSOptimizer, ::MOI.ObjectiveSense, ::MOI.OptimizationSense) end
MOIU.canload(::SCSOptimizer, ::MOI.ObjectiveFunction{MOI.ScalarAffineFunction{Float64}}) = true
function MOIU.load!(optimizer::SCSOptimizer, ::MOI.ObjectiveFunction, f::MOI.ScalarAffineFunction)
c0 = full(sparsevec(_varmap(f), f.coefficients, optimizer.data.n))
c0 = Vector(sparsevec(_varmap(f), f.coefficients, optimizer.data.n))
optimizer.data.objconstant = f.constant
optimizer.data.c = optimizer.maxsense ? -c0 : c0
end
Expand Down Expand Up @@ -352,7 +352,7 @@ end
function MOI.get(optimizer::SCSOptimizer, ::MOI.ConstraintPrimal, ci::CI{<:MOI.AbstractFunction, S}) where S <: MOI.AbstractSet
offset = constroffset(optimizer, ci)
rows = constrrows(optimizer, ci)
_unshift(optimizer, offset, unscalecoef(rows, reorderval(optimizer.sol.slack[offset + rows], S), S, length(rows)), S)
_unshift(optimizer, offset, unscalecoef(rows, reorderval(optimizer.sol.slack[offset .+ rows], S), S, length(rows)), S)
end

MOI.canget(optimizer::SCSOptimizer, ::MOI.DualStatus) = true
Expand All @@ -372,7 +372,7 @@ end
function MOI.get(optimizer::SCSOptimizer, ::MOI.ConstraintDual, ci::CI{<:MOI.AbstractFunction, S}) where S <: MOI.AbstractSet
offset = constroffset(optimizer, ci)
rows = constrrows(optimizer, ci)
unscalecoef(rows, reorderval(optimizer.sol.dual[offset + rows], S), S, length(rows))
unscalecoef(rows, reorderval(optimizer.sol.dual[offset .+ rows], S), S, length(rows))
end

MOI.canget(optimizer::SCSOptimizer, ::MOI.ResultCount) = true
Expand Down
30 changes: 25 additions & 5 deletions src/MPBWrapper.jl
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,14 @@
# MathProgBase.jl interface for the SCS.jl solver wrapper
#############################################################################

importall MathProgBase.SolverInterface
using Compat.LinearAlgebra: dot
using MathProgBase.SolverInterface

import MathProgBase.SolverInterface: ConicModel, LinearQuadraticModel,
getdual, getobjval, getsolution, getsolvetime, getvardual, loadproblem!,
numconstr, numvar, optimize!, setbvec!, setwarmstart!, status,
supportedcones

import Base.convert

# TODO: don't add to Base.convert!
Expand Down Expand Up @@ -145,14 +152,14 @@ function orderconesforscs(A_in, b_in, c_cones, v_cones)
A_t = spzeros(n,0)
b = zeros(0)
row_map_ind = zeros(Int, length(b_in))
row_map_type = Array{Symbol}(length(b_in))
row_map_type = Array{Symbol}(undef, length(b_in))
col_map_ind = zeros(Int, n)
col_map_type = Array{Symbol}(n)
col_map_type = Array{Symbol}(undef, n)

# First, count the total number of variables
num_vars = 0
for (cone, idxs) in v_cones
col_map_type[idxs] = cone
col_map_type[idxs] .= cone
num_vars += length(idxs)
end
@assert num_vars == n
Expand Down Expand Up @@ -429,10 +436,23 @@ function getvardual(m::SCSMathProgModel)
return dual
end

if VERSION >= v"0.7-"
function addoption!(m::SCSMathProgModel, option::Symbol, value)
nt = NamedTuple{(option,), Tuple{typeof(value)}}((value,))
m.options = pairs(merge(m.options.data, nt))
return m
end
else
function addoption!(m::SCSMathProgModel, option::Symbol, value)
push!(m.options, (option, value))
return m
end
end

# warmstart
# kwargs can be `primal_sol`, `dual_sol`, and `slack`
function setwarmstart!(m::SCSMathProgModel, primal_sol; kwargs...)
push!(m.options, (:warm_start, true))
addoption!(m, :warm_start, true)
m.primal_sol = primal_sol
for (k,v) in kwargs
setfield!(m, k, v)
Expand Down
6 changes: 4 additions & 2 deletions src/SCS.jl
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,14 @@ else
error("SCS not properly installed. Please run Pkg.build(\"SCS\") and restart julia")
end

import Base.Libdl: RTLD_LAZY, RTLD_DEEPBIND, RTLD_GLOBAL, dlopen
using Compat
using Compat.Libdl
using Compat.Sys: isunix

function __init__()
vnum = VersionNumber(SCS_version())
# default binaries need access to Julia's lapack symbols
if is_unix()
if isunix()
dlopen(Base.liblapack_name, RTLD_LAZY|RTLD_DEEPBIND|RTLD_GLOBAL)
end
depsdir = realpath(joinpath(dirname(@__FILE__),"..","deps"))
Expand Down
22 changes: 14 additions & 8 deletions src/c_wrapper.jl
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ macro compat_gc_preserve(args...)
vars = args[1:end-1]
body = args[end]
if VERSION > v"0.7.0-"
return esc(Expr(:macrocall, Expr(:., :Base, Base.Meta.quot(Symbol("@gc_preserve"))), __source__, args...))
return esc(Expr(:macrocall, Expr(:., :GC, Base.Meta.quot(Symbol("@preserve"))), __source__, args...))
else
return esc(body)
end
Expand Down Expand Up @@ -52,7 +52,13 @@ function SCS_solve(T::Union{Type{Direct}, Type{Indirect}},
cone = Ref(SCSCone(f, l, q, s, ep, ed, p))
info = Ref(SCSInfo())

if (:warm_start, true) in options && length(primal_sol) == n && length(dual_sol) == m && length(slack) == m
if VERSION >= v"0.7-"
ws = (:warm_start=>true) in options
else
ws = (:warm_start, true) in options
end

if ws && length(primal_sol) == n && length(dual_sol) == m && length(slack) == m
x = primal_sol
y = dual_sol
s = slack
Expand Down Expand Up @@ -82,26 +88,26 @@ for (T, lib) in zip([SCS.Direct, SCS.Indirect], [SCS.direct, SCS.indirect])
@eval begin
function SCS_init(::Type{$T}, data::Ref{SCSData}, cone::Ref{SCSCone}, info::Ref{SCSInfo})

p_work = ccall((:scs_init, $lib), Ptr{Void},
p_work = ccall((:scs_init, $lib), Ptr{Nothing},
(Ptr{SCSData}, Ptr{SCSCone}, Ptr{SCSInfo}),
data, cone, info)

return p_work
end

# solution struct is simple enough, we know it won't be modified by SCS so take by value
function SCS_solve(::Type{$T}, p_work::Ptr{Void}, data::Ref{SCSData}, cone::Ref{SCSCone}, solution::SCSSolution, info::Ref{SCSInfo})
function SCS_solve(::Type{$T}, p_work::Ptr{Nothing}, data::Ref{SCSData}, cone::Ref{SCSCone}, solution::SCSSolution, info::Ref{SCSInfo})

status = ccall((:scs_solve, $lib), Int,
(Ptr{Void}, Ptr{SCSData}, Ptr{SCSCone}, Ref{SCSSolution}, Ptr{SCSInfo}),
(Ptr{Nothing}, Ptr{SCSData}, Ptr{SCSCone}, Ref{SCSSolution}, Ptr{SCSInfo}),
p_work, data, cone, solution, info)

return status
end

function SCS_finish(::Type{$T}, p_work::Ptr{Void})
ccall((:scs_finish, $lib), Void,
(Ptr{Void}, ),
function SCS_finish(::Type{$T}, p_work::Ptr{Nothing})
ccall((:scs_finish, $lib), Nothing,
(Ptr{Nothing}, ),
p_work)
end
end
Expand Down
9 changes: 5 additions & 4 deletions src/types.jl
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
export SCSMatrix, SCSData, SCSSettings, SCSSolution, SCSInfo, SCSCone, SCSVecOrMatOrSparse
using Compat.SparseArrays

export SCSMatrix, SCSData, SCSSettings, SCSSolution, SCSInfo, SCSCone, SCSVecOrMatOrSparse

SCSVecOrMatOrSparse = Union{VecOrMat, SparseMatrixCSC{Float64,Int}}

Expand Down Expand Up @@ -68,9 +69,9 @@ struct SCSData
end

struct SCSSolution
x::Ptr{Void}
y::Ptr{Void}
s::Ptr{Void}
x::Ptr{Nothing}
y::Ptr{Nothing}
s::Ptr{Nothing}
end


Expand Down
4 changes: 2 additions & 2 deletions test/MPBWrapper.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
include("mpb_linear.jl")
end

import SCS
using Compat.Pkg: dir
@testset "MathProgBase" begin
include(joinpath(Pkg.dir("MathProgBase"),"test","conicinterface.jl"))
include(joinpath(dir("MathProgBase"),"test","conicinterface.jl"))
coniclineartest(SCS.SCSSolver(), duals=true, tol=1e-2)
conicSOCtest(SCS.SCSSolver(), duals=true, tol=1e-2)
conicEXPtest(SCS.SCSSolver(), duals=true, tol=1e-2)
Expand Down
3 changes: 0 additions & 3 deletions test/direct.jl
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
using SCS
using Base.Test

# Solve a trivial problem
A = reshape([1.0],(1,1))
solution = SCS_solve(SCS.Direct, 1, 1, A, [1.0], [1.0], 1, 0, Int[], Int[], 0, 0, Float64[]);
Expand Down
3 changes: 0 additions & 3 deletions test/indirect.jl
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
using SCS
using Base.Test

# Solve a trivial problem
A = reshape([1.0],(1,1))
solution = SCS_solve(SCS.Indirect, 1, 1, A, [1.0], [1.0], 1, 0, Int[], Int[], 0, 0, Float64[]);
Expand Down
4 changes: 2 additions & 2 deletions test/mpb_linear.jl
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@
# Test the MathProgBase.jl interface for the SCS.jl solver wrapper
#############################################################################

using Base.Test
using MathProgBase
using SCS
using Compat.LinearAlgebra
using Compat.SparseArrays

solver = SCSSolver()
objtol = 1e-4
Expand Down
9 changes: 3 additions & 6 deletions test/options.jl
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,7 @@
# Tests the ability to pass options
#############################################################################

using Base.Test
using MathProgBase.SolverInterface
using SCS

using MathProgBase

# The normal test
A = [1.0 1.0 0.0 0.0 0.0;
Expand All @@ -33,8 +30,8 @@ MathProgBase.optimize!(m)
@test isapprox(MathProgBase.getobjval(m), -99.0, atol=1e-5)

# With a warmstart from the eps = 1e-8 solution, solution should be extremely accurate even after 1 iteration
push!(m.options, (:warm_start, true))
push!(m.options, (:max_iters, 1))
SCS.addoption!(m, :warm_start, true)
SCS.addoption!(m, :max_iters, 1)
MathProgBase.optimize!(m)
@test isapprox(MathProgBase.getobjval(m), -99.0, atol=1e-5)

Expand Down
3 changes: 2 additions & 1 deletion test/runtests.jl
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Base.Test
using Compat.Test
using SCS

tests = ["direct.jl",
"indirect.jl",
Expand Down
639 changes: 612 additions & 27 deletions test/test_problems.jl

Large diffs are not rendered by default.

0 comments on commit b149b73

Please sign in to comment.