Skip to content

Commit

Permalink
Fixing the issue #447 and updating the examples in docstrings for run…
Browse files Browse the repository at this point in the history
…_tests() and benchmark_suite() (#448)

* Fixed the issue #447.

* Updated syntax for optimizers in the examples in run_tests() and benchmark_suite().

* Update src/problem_depot/problems/sdp.jl

* Apply suggestions from code review

Co-authored-by: Eric Hanson <5846501+ericphanson@users.noreply.github.com>

* Updated tests according to the change in the problem formulation (changed A⪯λ to A⪯λ*eye(2) in the sdp_min_maxeig_canon_lmi problem).

* Incorporation of Eric's suggestion of a nicer (because just single) use of output() at the end of evaluate().

Co-authored-by: Eric Hanson <5846501+ericphanson@users.noreply.github.com>
  • Loading branch information
hurak and ericphanson committed Jul 19, 2021
1 parent 52e4eab commit 2493bb1
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 20 deletions.
8 changes: 5 additions & 3 deletions src/atoms/affine/index.jl
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,13 @@ function curvature(x::IndexAtom)
end

function evaluate(x::IndexAtom)
if x.inds === nothing
return getindex(evaluate(x.children[1]), x.rows, x.cols)
result = if x.inds === nothing
getindex(evaluate(x.children[1]), x.rows, x.cols)
else
return getindex(evaluate(x.children[1]), x.inds)
getindex(evaluate(x.children[1]), x.inds)
end
# `output` needed to convert a 1-element array to a scalar (https://github.com/jump-dev/Convex.jl/issues/447)
return output(result)
end

function conic_form!(x::IndexAtom, unique_conic_forms::UniqueConicForms)
Expand Down
32 changes: 16 additions & 16 deletions src/problem_depot/problem_depot.jl
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ eye(n) = Matrix{Float64}(I, n, n)
A "depot" of Convex.jl problems, subdivided into categories.
Each problem is stored as a function with the signature
f(handle_problem!, ::Val{test}, atol, rtol, ::Type{T}) where {T, test}
where `handle_problem!` specifies what to do with the `Problem` instance
(e.g., `solve!` it with a chosen solver), an option `test` to choose
whether or not to test the values (assuming it has been solved),
Expand All @@ -45,10 +45,10 @@ const PROBLEMS = Dict{String, Dict{String, Function}}()

"""
foreach_problem(apply::Function, [class::String],
problems::Union{Nothing, Vector{String}, Vector{Regex}} = nothing;
problems::Union{Nothing, Vector{String}, Vector{Regex}} = nothing;
exclude::Vector{Regex} = Regex[])
Provides a convience method for iterating over problems in [`PROBLEMS`](@ref).
Provides a convience method for iterating over problems in [`PROBLEMS`](@ref).
For each problem in [`PROBLEMS`](@ref), apply the function `apply`, which
takes two arguments: the name of the function associated to the problem,
and the function associated to the problem itself.
Expand All @@ -58,16 +58,16 @@ problems (`class` should satsify `class ∈ keys(PROBLEMS)`), and pass third
argument `problems` to only allow certain problems (specified by exact names or
regex). Use the `exclude` keyword argument to exclude problems by regex.
"""
function foreach_problem( apply::Function,
problems::Union{Nothing, Vector{String}, Vector{Regex}} = nothing;
function foreach_problem( apply::Function,
problems::Union{Nothing, Vector{String}, Vector{Regex}} = nothing;
exclude::Vector{Regex} = Regex[])
for class in keys(PROBLEMS)
any(occursin.(exclude, Ref(class))) && continue
foreach_problem(apply, class, problems; exclude=exclude)
end
end

function foreach_problem( apply::Function,
function foreach_problem( apply::Function,
class::String,
problems::Union{Nothing, Vector{String}, Vector{Regex}} = nothing;
exclude::Vector{Regex} = Regex[])
Expand All @@ -85,9 +85,9 @@ end
"""
run_tests(
handle_problem!::Function;
problems::Union{Nothing, Vector{String}, Vector{Regex}} = nothing;
problems::Union{Nothing, Vector{String}, Vector{Regex}} = nothing;
exclude::Vector{Regex} = Regex[],
T=Float64, atol=1e-3, rtol=0.0,
T=Float64, atol=1e-3, rtol=0.0,
)
Run a set of tests. `handle_problem!` should be a function that takes one
Expand All @@ -105,12 +105,12 @@ MathOptInterface model, but not for the actual problem data.
```julia
run_tests(exclude=[r"mip"]) do p
solve!(p, SCSSolver(verbose=0))
solve!(p, SCS.Optimizer; silent_solver=true)
end
```
"""
function run_tests( handle_problem!::Function,
problems::Union{Nothing, Vector{String}, Vector{Regex}} = nothing;
function run_tests( handle_problem!::Function,
problems::Union{Nothing, Vector{String}, Vector{Regex}} = nothing;
exclude::Vector{Regex} = Regex[], T=Float64, atol=1e-3, rtol=0.0)
push!(exclude, r"benchmark")
for class in keys(PROBLEMS)
Expand All @@ -129,10 +129,10 @@ end
"""
benchmark_suite(
handle_problem!::Function,
problems::Union{Nothing, Vector{String}, Vector{Regex}} = nothing;
problems::Union{Nothing, Vector{String}, Vector{Regex}} = nothing;
exclude::Vector{Regex} = Regex[],
test = Val(false),
T=Float64, atol=1e-3, rtol=0.0,
T=Float64, atol=1e-3, rtol=0.0,
)
Create a benchmark_suite of benchmarks. `handle_problem!` should be a function
Expand All @@ -151,12 +151,12 @@ MathOptInterface model, but not for the actual problem data.
```julia
benchmark_suite(exclude=[r"mip"]) do p
solve!(p, SCSSolver(verbose=0))
solve!(p, SCS.Optimizer; silent_solver=true)
end
```
"""
function benchmark_suite(handle_problem!::Function,
problems::Union{Nothing, Vector{String}, Vector{Regex}} = nothing;
problems::Union{Nothing, Vector{String}, Vector{Regex}} = nothing;
exclude::Vector{Regex} = Regex[],
T=Float64, atol=1e-3, rtol=0.0, test = Val(false))
group = BenchmarkGroup()
Expand Down
34 changes: 33 additions & 1 deletion src/problem_depot/problems/sdp.jl
Original file line number Diff line number Diff line change
Expand Up @@ -473,7 +473,7 @@ end
l,v = eigen(A)
posA = v*Diagonal(max.(l,0))*v'


if test
real_diff = real.(evaluate(x)) - real.(posA)
imag_diff = imag.(evaluate(x)) - imag.(posA)
Expand Down Expand Up @@ -1361,3 +1361,35 @@ end
end
end
end

@add_problem sdp function sdp_min_maxeig_canon_lmi(handle_problem!, ::Val{test}, atol, rtol, ::Type{T}) where {T, test}
# Minimize the maximum eigenvalue of an affine matrix function of a vector argument. Formulated
# as a linear optimization subject to a canonical LMI (SDP) constraint:
#
# minimize λ
# subject to A(x) ⪯ λ*I
# where x is a vector in Rⁿ and the matrix function A(x) = A₀ + A₁x₁ + A₂x₂ + … + Aₙxₙ.
#
# Besides serving as a benchmark, it also tests the solution of the Issue
# https://github.com/jump-dev/Convex.jl/issues/447
# (the issues boils down to evaluation of `A₁x₁`, because `x₁` was a matrix of size (1,1)).

A₀ = [1.0 2.0; 2.0 3.0]
A₁ = [1.0 0.0; 0.0 -1.0]
A₂ = [4.0 5.0; 5.0 -6.0]

x = Variable(2)
λ = Variable()

A = A₀ + A₁*x[1] + A₂*x[2]

p = minimize(λ,Aλ*eye(2); numeric_type=T)

handle_problem!(p)

if test
@test λ.value 2.400000051025101 atol=atol rtol=rtol
@test x.value [3.0000000535867315, -0.4000000018585541] atol=atol rtol=rtol
@test evaluate(A) [2.400000046152515 -9.292770553059881e-9; -9.292770553059881e-9 2.399999957564593] atol=atol rtol=rtol
end
end

0 comments on commit 2493bb1

Please sign in to comment.