Skip to content

Commit c2e88b2

Browse files
authored
Merge pull request #157 from JuliaPolyhedra/bl/jump0.19
Update to JuMP v0.19
2 parents fc51bb5 + f73583b commit c2e88b2

31 files changed

+797
-758
lines changed

.travis.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ os:
44
- linux
55
- osx
66
julia:
7-
- 0.7
87
- 1.0
98
- 1.1
109
#addons:

REQUIRE

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
julia 0.7
1+
julia 1.0
22
StaticArrays 0.5
33
MathProgBase 0.5.10 0.8
4-
JuMP 0.16 0.19
4+
JuMP 0.19
55
GeometryTypes 0.4
66
RecipesBase 0.2

appveyor.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
environment:
22
matrix:
3-
- julia_version: 0.7
43
- julia_version: 1.0
54

65
platform:

docs/src/optimization.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ Polyhedra.MathProgBase.linprog
1010

1111
If the V-representation of the polyhedron has been computed, it can be used to solve the linear program.
1212
```@docs
13-
VRepSolver
13+
VRepOptimizer
1414
```
1515

1616
Otherwise, any programming solver implementing the [MathProgBase](https://github.com/JuliaOpt/MathProgBase.jl) interface can be used. See [here](http://www.juliaopt.org/) for a list of available solvers.
@@ -46,5 +46,5 @@ In fact, the MathProgBase representation of the feasible set of a linear program
4646
\end{align*}
4747
```
4848

49-
has `LPHRepresentation` as a corresponding H-representation.
50-
A JuMP model can be converted to this representation using `LPHRepresentation(m)`.
49+
has `LPHRep` as a corresponding H-representation.
50+
A JuMP model can be converted to this representation using `LPHRep(m)`.

src/Polyhedra.jl

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
__precompile__()
2-
31
module Polyhedra
42

53
using SparseArrays
@@ -10,9 +8,9 @@ export Polyhedron
108
abstract type Library end
119
abstract type Polyhedron{T} end
1210

13-
import MathProgBase
14-
const MPB = MathProgBase
15-
const MPBSI = MPB.SolverInterface
11+
import JuMP
12+
const Solver = JuMP.OptimizerFactory
13+
const SolverOrNot = Union{Nothing, Solver}
1614

1715
coefficient_type(::Union{AbstractVector{T}, Type{<:AbstractVector{T}}}) where T = T
1816
similar_type(::Type{<:Vector}, ::Int, ::Type{T}) where T = Vector{T}
@@ -82,9 +80,8 @@ include("fulldim.jl")
8280

8381
# Optimization
8482
include("opt.jl")
85-
include("lpqp_to_polyhedra.jl")
86-
include("polyhedra_to_lpqp.jl")
87-
include("vrepsolver.jl")
83+
include("polyhedra_to_lp_bridge.jl")
84+
include("vrep_optimizer.jl")
8885
include("default.jl")
8986

9087
# Visualization

src/center.jl

Lines changed: 35 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,55 +1,58 @@
11
export hchebyshevcenter, vchebyshevcenter, chebyshevcenter
22
using JuMP
3+
34
"""
45
hchebyshevcenter(p::HRep[, solver])
56
67
Return a tuple with the center and radius of the largest euclidean ball contained in the polyhedron `p`.
78
Throws an error if the polyhedron is empty or if the radius is infinite.
89
"""
9-
function hchebyshevcenter(p::HRep, solver=Polyhedra.solver(p))
10-
m = Model(solver=solver)
11-
c = @variable m [1:fulldim(p)]
10+
function hchebyshevcenter(p::HRep, solver=Polyhedra.default_solver(p))
11+
model = JuMP.Model(solver)
12+
c = JuMP.@variable(model, [1:fulldim(p)])
1213
for hp in hyperplanes(p)
13-
a = Vector{Float64}(hp.a)
14-
β = Float64(hp.β)
15-
@constraint m dot(a, c) == β
14+
a = convert(Vector{Float64}, hp.a)
15+
β = convert(Float64, hp.β)
16+
JuMP.@constraint(model, dot(a, c) == β)
1617
end
17-
@variable m r[1:nhalfspaces(p)] >= 0
18+
JuMP.@variable(model, r[1:nhalfspaces(p)] >= 0)
1819
for (i, hs) in enumerate(halfspaces(p))
19-
a = Vector{Float64}(hs.a)
20-
β = Float64(hs.β)
21-
@constraint m dot(a, c) + r[i] * norm(a, 2) <= β
20+
a = convert(Vector{Float64}, hs.a)
21+
β = convert(Float64, hs.β)
22+
JuMP.@constraint(model, dot(a, c) + r[i] * norm(a, 2) <= β)
2223
end
23-
@variable m minr >= 0
24-
@constraint m minr .<= r
25-
@objective m Max minr
26-
status = solve(m)
27-
if status != :Optimal
28-
if status == :Infeasible
29-
error("An empty polyhedron has no H-Chebyshev center")
30-
elseif status == :Unbounded
31-
error("The polyhedron contains euclidean ball of arbitrary large radius")
24+
JuMP.@variable(model, minr >= 0)
25+
JuMP.@constraint(model, minr .<= r)
26+
JuMP.@objective(model, Max, minr)
27+
JuMP.optimize!(model)
28+
term = JuMP.termination_status(model)
29+
if term != MOI.OPTIMAL
30+
if term == MOI.INFEASIBLE
31+
error("An empty polyhedron has no H-Chebyshev center.")
32+
elseif term == MOI.DUAL_INFEASIBLE
33+
error("The polyhedron contains euclidean ball of arbitrary large radius.")
3234
else
33-
error("Solver returned $status when computing the H-Chebyshev center")
35+
error("Solver returned $term when computing the H-Chebyshev center.")
3436
end
3537
end
36-
@constraint m minr == getvalue(minr)
37-
@variable m maxr >= 0
38-
@constraint m maxr .>= r
39-
@objective m Min maxr
40-
status = solve(m)
41-
@assert status == :Optimal
42-
(getvalue(c), getvalue(minr))
38+
JuMP.@constraint(model, minr == JuMP.value(minr))
39+
JuMP.@variable(model, maxr >= 0)
40+
JuMP.@constraint(model, maxr .>= r)
41+
JuMP.@objective(model, Min, maxr)
42+
JuMP.optimize!(model)
43+
term = JuMP.termination_status(model)
44+
@assert term == MOI.OPTIMAL
45+
return (JuMP.value.(c), JuMP.value(minr))
4346
end
4447

45-
# TODO solver here should not be VRepSolver
48+
# TODO solver here should not be VRepOptimizer
4649
"""
4750
vchebyshevcenter(p::VRep[, solver])
4851
4952
Return a tuple with the center and radius of the smallest euclidean ball containing the polyhedron `p`.
5053
Throws an error if the polyhedron is empty or if the radius is infinite (i.e. `p` is not a polytope, it contains rays).
5154
"""
52-
function vchebyshevcenter(p::VRep, solver=Polyhedra.solver(p))
55+
function vchebyshevcenter(p::VRep, solver=Polyhedra.default_solver(p))
5356
error("TODO")
5457
end
5558

@@ -58,12 +61,12 @@ end
5861
5962
If `p` is a H-representation or is a polyhedron for which the H-representation has already been computed, calls `hchebyshevcenter`, otherwise, call `vchebyshevcenter`.
6063
"""
61-
function chebyshevcenter(p::Polyhedron, solver=Polyhedra.solver(p))
64+
function chebyshevcenter(p::Polyhedron, solver=Polyhedra.default_solver(p))
6265
if hrepiscomputed(p)
6366
hchebyshevcenter(p, solver)
6467
else
6568
vchebyshevcenter(p, solver)
6669
end
6770
end
68-
chebyshevcenter(p::HRepresentation, solver=Polyhedra.solver(p)) = hchebyshevcenter(p, solver)
69-
chebyshevcenter(p::VRepresentation, solver=Polyhedra.solver(p)) = vchebyshevcenter(p, solver)
71+
chebyshevcenter(p::HRepresentation, solver=Polyhedra.default_solver(p)) = hchebyshevcenter(p, solver)
72+
chebyshevcenter(p::VRepresentation, solver=Polyhedra.default_solver(p)) = vchebyshevcenter(p, solver)

src/default.jl

Lines changed: 33 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ end
1313
function default_type(d::StaticArrays.Size{(1,)}, ::Type{T}) where T
1414
return Interval{T, StaticArrays.SVector{1, T}, typeof(d)}
1515
end
16-
function default_type(d::Int, ::Type{T}) where T
17-
if d == 1
16+
function default_type(d::Integer, ::Type{T}) where T
17+
if isone(d)
1818
return Interval{T, Vector{T}, typeof(d)}
1919
else
2020
return DefaultPolyhedron{T, Intersection{T, Vector{T}, typeof(d)}, Hull{T, Vector{T}, typeof(d)}}
@@ -42,8 +42,8 @@ _default_type(::Type{T}) where T = T
4242
_default_type(::Type{AbstractFloat}) = Float64
4343
default_library(::StaticArrays.Size, T::Type) = DefaultLibrary{_default_type(T)}()
4444
default_library(::StaticArrays.Size{(1,)}, T::Type) = IntervalLibrary{_default_type(T)}()
45-
function default_library(d::Int, ::Type{T}) where T
46-
if d == 1
45+
function default_library(d::Integer, ::Type{T}) where T
46+
if isone(d)
4747
return IntervalLibrary{_default_type(T)}()
4848
else
4949
return DefaultLibrary{_default_type(T)}()
@@ -78,35 +78,48 @@ default_solver(p::Rep) = nothing
7878
function default_solver(p::Rep, ps::Rep...)
7979
s = default_solver(p)
8080
if s === nothing
81-
default_solver(ps...)
81+
return default_solver(ps...)
8282
else
83-
s
83+
return s
8484
end
8585
end
8686

8787
"""
88-
solver(p::Rep, solver::MathProgBase.AbstractMathProgSolver=default_solver(p))
89-
90-
If the V-representation of `p` has been computed, returns `VRepSolver()`, otherwise, returns `solver`.
88+
linear_objective_solver(p::Rep, solver::Union{Nothing, JuMP.OptimizerFactory}=default_solver(p))
89+
90+
Return the solver to use for optimizing a linear objective over the polyhedron `p`, i.e.
91+
```julia
92+
model = Model(solver)
93+
x = @variable(model, [1:fulldim(p)])
94+
@constraint(model, x in p)
95+
@objective(model, c ⋅ x)
96+
```
97+
for some vector `c`.
98+
99+
By default, if the V-representation of `p` has been computed, it returns
100+
`VRepOptimizer()`, otherwise, it returns `solver`.
101+
102+
If the problem has constraints different to `x in p`, use `default_solver(p)` instead
103+
as the fact that the V-representation of `p` has been computed does not help.
91104
"""
92-
function solver(p::Rep, solver::Union{Nothing, MPB.AbstractMathProgSolver}=default_solver(p))
105+
function linear_objective_solver(p::Rep{T}, solver::SolverOrNot=default_solver(p)) where T
93106
if vrepiscomputed(p)
94-
VRepSolver()
107+
return with_optimizer(VRepOptimizer{T})
95108
else
96-
solver
109+
return solver
97110
end
98111
end
99112

100-
solver(v::VRepresentation, solver::Union{Nothing, MPB.AbstractMathProgSolver}=default_solver(v)) = VRepSolver()
101-
solver(h::HRepresentation, solver::Union{Nothing, MPB.AbstractMathProgSolver}=default_solver(h)) = solver
113+
linear_objective_solver(v::VRepresentation{T}, solver::SolverOrNot=default_solver(v)) where {T} = with_optimizer(VRepOptimizer{T})
114+
linear_objective_solver(h::HRepresentation, solver::SolverOrNot=default_solver(h)) = solver
102115

103116
_promote_reptype(P::Type{<:HRep}, ::Type{<:HRep}) = P
104117
_promote_reptype(P::Type{<:VRep}, ::Type{<:VRep}) = P
105118
# Breaks ambiguity with above two methods
106119
_promote_reptype(P::Type{<:Polyhedron}, ::Type{<:Polyhedron}) = P
107120

108121
function promote_reptype(P1::Type{<:Rep}, P2::Type{<:Rep})
109-
_promote_reptype(P1, P2)
122+
return _promote_reptype(P1, P2)
110123
end
111124
promote_reptype(P1::Type{<:Rep}, P2::Type{<:Rep}, P::Type{<:Rep}...) = promote_reptype(promote_reptype(P1, P2), P...)
112125
promote_reptype(P::Type{<:Rep}) = P
@@ -121,13 +134,13 @@ function constructpolyhedron(RepT::Type{<:Rep{T}}, d::FullDim, p::Tuple{Vararg{R
121134
return RepT(d, it..., solver=solver)
122135
end
123136
end
124-
RepT(d, it...)::RepT # FIXME without this type annotation even convexhull(::PointsHull{2,Int64,Array{Int64,1}}, ::PointsHull{2,Int64,Array{Int64,1}}) is not type stable, why ?
137+
return RepT(d, it...)::RepT # FIXME without this type annotation even convexhull(::PointsHull{2,Int64,Array{Int64,1}}, ::PointsHull{2,Int64,Array{Int64,1}}) is not type stable, why ?
125138
end
126139

127140
function default_similar(p::Tuple{Vararg{Rep}}, d::FullDim, ::Type{T}, it::It{T}...) where T
128141
# Some types in p may not support `d` or `T` so we call `similar_type` after `promote_reptype`
129142
RepT = similar_type(promote_reptype(typeof.(p)...), d, T)
130-
constructpolyhedron(RepT, d, p, it...)
143+
return constructpolyhedron(RepT, d, p, it...)
131144
end
132145

133146
"""
@@ -138,13 +151,13 @@ The type of the result will be chosen closer to the type of `p[1]`.
138151
"""
139152
Base.similar(p::Tuple{Vararg{Rep}}, d::FullDim, ::Type{T}, it::It{T}...) where {T} = default_similar(p, d, T, it...)
140153
function promote_coefficient_type(p::Tuple{Vararg{Rep}})
141-
promote_type(coefficient_type.(p)...)
154+
return promote_type(coefficient_type.(p)...)
142155
end
143156
function Base.similar(p::Tuple{Vararg{Rep}}, d::FullDim, it::It...)
144157
T = promote_coefficient_type(p)
145-
similar(p, d, T, it...)
158+
return similar(p, d, T, it...)
146159
end
147160
function Base.similar(p::Tuple{Vararg{Rep}}, it::It...)
148-
similar(p, FullDim(p[1]), it...)
161+
return similar(p, FullDim(p[1]), it...)
149162
end
150163
Base.similar(p::Rep, args...) = similar((p,), args...)

src/defaultlibrary.jl

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ Default library for polyhedra of dimension larger than 1 ([`IntervalLibrary`](@r
77
The library implements the bare minimum and uses the fallback implementation for all operations.
88
"""
99
struct DefaultLibrary{T} <: Library
10-
solver::Union{Nothing, MPB.AbstractMathProgSolver}
10+
solver::SolverOrNot
1111
function DefaultLibrary{T}(solver=nothing) where T
1212
new{T}(solver)
1313
end
@@ -18,21 +18,21 @@ similar_library(lib::DefaultLibrary, d::FullDim, ::Type{T}) where T = default_li
1818
mutable struct DefaultPolyhedron{T, HRepT<:HRepresentation{T}, VRepT<:VRepresentation{T}} <: Polyhedron{T}
1919
hrep::Union{HRepT, Nothing}
2020
vrep::Union{VRepT, Nothing}
21-
solver::Union{Nothing, MPB.AbstractMathProgSolver}
22-
function DefaultPolyhedron{T, HRepT, VRepT}(hrep::Union{HRepT, Nothing}, vrep::Union{VRepT, Nothing}, solver::Union{Nothing, MPB.AbstractMathProgSolver}) where {T, HRepT<:HRepresentation{T}, VRepT<:VRepresentation{T}}
21+
solver::SolverOrNot
22+
function DefaultPolyhedron{T, HRepT, VRepT}(hrep::Union{HRepT, Nothing}, vrep::Union{VRepT, Nothing}, solver::SolverOrNot) where {T, HRepT<:HRepresentation{T}, VRepT<:VRepresentation{T}}
2323
new{T, HRepT, VRepT}(hrep, vrep, solver)
2424
end
2525
end
26-
function DefaultPolyhedron{T, HRepT, VRepT}(hrep::HRepT, solver::Union{Nothing, MPB.AbstractMathProgSolver}) where {T, HRepT<:HRepresentation{T}, VRepT<:VRepresentation{T}}
26+
function DefaultPolyhedron{T, HRepT, VRepT}(hrep::HRepT, solver::SolverOrNot) where {T, HRepT<:HRepresentation{T}, VRepT<:VRepresentation{T}}
2727
DefaultPolyhedron{T, HRepT, VRepT}(hrep, nothing, solver)
2828
end
29-
function DefaultPolyhedron{T, HRepT, VRepT}(vrep::VRepT, solver::Union{Nothing, MPB.AbstractMathProgSolver}) where {T, HRepT<:HRepresentation{T}, VRepT<:VRepresentation{T}}
29+
function DefaultPolyhedron{T, HRepT, VRepT}(vrep::VRepT, solver::SolverOrNot) where {T, HRepT<:HRepresentation{T}, VRepT<:VRepresentation{T}}
3030
DefaultPolyhedron{T, HRepT, VRepT}(nothing, vrep, solver)
3131
end
32-
function DefaultPolyhedron{T, HRepT, VRepT}(hrep::HRepresentation, solver::Union{Nothing, MPB.AbstractMathProgSolver}) where {T, HRepT<:HRepresentation{T}, VRepT<:VRepresentation{T}}
32+
function DefaultPolyhedron{T, HRepT, VRepT}(hrep::HRepresentation, solver::SolverOrNot) where {T, HRepT<:HRepresentation{T}, VRepT<:VRepresentation{T}}
3333
DefaultPolyhedron{T, HRepT, VRepT}(convert(HRepT, hrep), solver)
3434
end
35-
function DefaultPolyhedron{T, HRepT, VRepT}(vrep::VRepresentation, solver::Union{Nothing, MPB.AbstractMathProgSolver}) where {T, HRepT<:HRepresentation{T}, VRepT<:VRepresentation{T}}
35+
function DefaultPolyhedron{T, HRepT, VRepT}(vrep::VRepresentation, solver::SolverOrNot) where {T, HRepT<:HRepresentation{T}, VRepT<:VRepresentation{T}}
3636
DefaultPolyhedron{T, HRepT, VRepT}(convert(VRepT, vrep), solver)
3737
end
3838

@@ -54,13 +54,13 @@ function DefaultPolyhedron{T, HRepT, VRepT}(d::FullDim, vits::VIt...; solver=not
5454
end
5555

5656
# Need fulltype in case the use does `intersect!` with another element
57-
DefaultPolyhedron{T}(rep::Representation, solver::Union{Nothing, MPB.AbstractMathProgSolver}) where {T} = DefaultPolyhedron{T}(change_coefficient_type(rep, T), solver)
58-
function DefaultPolyhedron{T}(rep::HRepresentation{T}, solver::Union{Nothing, MPB.AbstractMathProgSolver}) where {T}
57+
DefaultPolyhedron{T}(rep::Representation, solver::SolverOrNot) where {T} = DefaultPolyhedron{T}(change_coefficient_type(rep, T), solver)
58+
function DefaultPolyhedron{T}(rep::HRepresentation{T}, solver::SolverOrNot) where {T}
5959
HRepT = fulltype(typeof(rep))
6060
VRepT = dualtype(HRepT)
6161
DefaultPolyhedron{T, HRepT, VRepT}(rep, solver)
6262
end
63-
function DefaultPolyhedron{T}(rep::VRepresentation{T}, solver::Union{Nothing, MPB.AbstractMathProgSolver}) where {T}
63+
function DefaultPolyhedron{T}(rep::VRepresentation{T}, solver::SolverOrNot) where {T}
6464
VRepT = fulltype(typeof(rep))
6565
HRepT = dualtype(VRepT)
6666
DefaultPolyhedron{T, HRepT, VRepT}(rep, solver)

src/dimension.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ fulldim(p) = fulldim(FullDim(p))
4545

4646
function fulldim end
4747

48-
fulldim(N::Int) = N
48+
fulldim(N::Integer) = convert(Int, N)
4949
fulldim(::StaticArrays.Size{N}) where N = N[1]
5050

5151
neg_fulldim(N::Int) = -N

src/jump.jl

Lines changed: 5 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -6,24 +6,11 @@ using JuMP
66
Builds an H-representation from the feasibility set of the JuMP model `model`.
77
Note that if non-linear constraint are present in the model, they are ignored.
88
"""
9-
hrep(model::JuMP.Model) = LPHRepresentation(model)
9+
hrep(model::JuMP.Model) = LPHRep(model)
1010

11-
function LPHRepresentation(model::JuMP.Model)
12-
# Inspired from Joey Huchette's code in ConvexHull.jl
13-
A = JuMP.prepConstrMatrix(model)
14-
c = JuMP.prepAffObjective(model)
15-
lb, ub = JuMP.prepConstrBounds(model)
16-
l, u = model.colLower, model.colUpper
11+
LPHRep(model::JuMP.Model) = LPHRep(backend(model))
1712

18-
m, n = size(A)
19-
@assert m == length(lb) == length(ub)
20-
@assert model.nlpdata == nothing
21-
@assert isempty(model.quadconstr)
22-
@assert isempty(model.sosconstr)
23-
24-
LPHRepresentation(A, l, u, lb, ub)
25-
end
26-
27-
function polyhedron(model::JuMP.Model, lib::Library=default_library(FullDim{model.numCols}(), Float64))
28-
polyhedron(LPHRepresentation(model), lib)
13+
function polyhedron(model::JuMP.Model,
14+
lib::Library=default_library(FullDim(JuMP.num_variables(model)), Float64))
15+
polyhedron(LPHRep(model), lib)
2916
end

0 commit comments

Comments
 (0)