Skip to content

Commit

Permalink
Add VariableInfo
Browse files Browse the repository at this point in the history
  • Loading branch information
blegat committed Apr 17, 2018
1 parent a418b68 commit 7e4a0d4
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 89 deletions.
43 changes: 28 additions & 15 deletions src/macros.jl
Expand Up @@ -873,34 +873,45 @@ esc_nonconstant(x::Number) = x
esc_nonconstant(x::Expr) = isexpr(x,:quote) ? x : esc(x)
esc_nonconstant(x) = esc(x)

mutable struct VariableInfo{S, T, U, V}
haslb::Bool
lowerbound::S
hasub::Bool
upperbound::T
hasfix::Bool
fixedvalue::U
binary::Bool
integer::Bool
hasstart::Bool
start::V
end

# Returns the type of what `constructvariable!` would return with these starting positional arguments.
variabletype(m::Model) = Variable
# Returns a new variable belonging to the model `m`. Additional positional arguments can be used to dispatch the call to a different method.
# The return type should only depends on the positional arguments for `variabletype` to make sense.
function constructvariable!(m::Model, _error::Function, haslb::Bool, lowerbound::Number, hasub::Bool, upperbound::Number,
hasfix::Bool, fixedvalue::Number, binary::Bool, integer::Bool, name::String,
hasstart::Bool, start::Number; extra_kwargs...)
function constructvariable!(m::Model, _error::Function, info::VariableInfo, name::String; extra_kwargs...)
for (kwarg, _) in extra_kwargs
_error("Unrecognized keyword argument $kwarg")
end
v = Variable(m)
if haslb
setlowerbound(v, lowerbound)
if info.haslb
setlowerbound(v, info.lowerbound)
end
if hasub
setupperbound(v, upperbound)
if info.hasub
setupperbound(v, info.upperbound)
end
if hasfix
fix(v, fixedvalue)
if info.hasfix
fix(v, info.fixedvalue)
end
if binary
if info.binary
setbinary(v)
end
if integer
if info.integer
setinteger(v)
end
if hasstart
setstartvalue(v, start)
if info.hasstart
setstartvalue(v, info.start)
end
if name != EMPTYSTRING
setname(v, name)
Expand Down Expand Up @@ -1095,10 +1106,12 @@ macro variable(args...)
end
extra = esc.(filter(ex -> !(ex in [:Int,:Bin]), extra))

info = :(VariableInfo($haslb, $lb, $hasub, $ub, $hasfix, $fixedvalue, $binary, $integer, $hasstart, $value))

if isa(var,Symbol)
# Easy case - a single variable
sdp && _error("Cannot add a semidefinite scalar variable")
variablecall = :( constructvariable!($m, $(extra...), $_error, $haslb, $lb, $hasub, $ub, $hasfix, $fixedvalue, $binary, $integer, $basename, $hasstart, $value) )
variablecall = :( constructvariable!($m, $(extra...), $_error, $info, $basename) )
addkwargs!(variablecall, extra_kwargs)
code = :($variable = $variablecall)
if !anonvar
Expand All @@ -1118,7 +1131,7 @@ macro variable(args...)
clear_dependencies(i) = (isdependent(idxvars,idxsets[i],i) ? () : idxsets[i])

# Code to be used to create each variable of the container.
variablecall = :( constructvariable!($m, $(extra...), $_error, $haslb, $lb, $hasub, $ub, $hasfix, $fixedvalue, $binary, $integer, $(namecall(basename, idxvars)), $hasstart, $value) )
variablecall = :( constructvariable!($m, $(extra...), $_error, $info, $(namecall(basename, idxvars))) )
addkwargs!(variablecall, extra_kwargs)
code = :( $(refcall) = $variablecall )
# Determine the return type of constructvariable!. This is needed to create the container holding them.
Expand Down
39 changes: 39 additions & 0 deletions test/macros.jl
Expand Up @@ -7,4 +7,43 @@
ex = @expression(m, sum(i+j+k for ((i,j),k) in d))
@test ex == 6
end

@testset "Extension of @variable with constructvariable! #1029" begin
JuMP.variabletype(m::Model, ::Type{MyVariable}) = MyVariable
function JuMP.constructvariable!(m::Model, ::Type{MyVariable}, _error::Function, args...; test_kw::Int = 0)
MyVariable(args..., test_kw)
end
m = Model()
@variable(m, 1 <= x <= 2, MyVariable, binary = true, test_kw = 1, start = 3)
@test isa(x, MyVariable)
@test x.info.haslb
@test x.info.lowerbound == 1
@test x.info.hasub
@test x.info.upperbound == 2
@test !x.info.hasfix
@test isnan(x.info.fixedvalue)
@test x.info.binary
@test !x.info.integer
@test x.info.hasstart
@test x.info.start == 3
@test x.name == "x"
@test x.test_kw == 1
@variable(m, y[1:3] >= 0, MyVariable, test_kw = 2)
@test isa(y, Vector{MyVariable})
for i in 1:3
@test y[i].info.haslb
@test y[i].info.lowerbound == 0
@test !y[i].info.hasub
@test y[i].info.upperbound == Inf
@test !y[i].info.hasfix
@test isnan(y[i].info.fixedvalue)
@test !y[i].info.binary
@test !y[i].info.integer
@test !y[i].info.hasstart
@test isnan(y[i].info.start)
@test y[i].name == "y[$i]"
@test y[i].test_kw == 2
end
end

end
26 changes: 0 additions & 26 deletions test/old/macros.jl
Expand Up @@ -773,32 +773,6 @@ end
@test getupperbound(z) == 1
end

@testset "Extension of @variable with constructvariable! #1029" begin
JuMP.variabletype(m::Model, ::Type{MyVariable}) = MyVariable
function JuMP.constructvariable!(m::Model, ::Type{MyVariable}, _error::Function, lowerbound::Number, upperbound::Number, category::Symbol, basename::AbstractString, start::Number; test_kw::Int = 0)
MyVariable(lowerbound, upperbound, category, basename, start, test_kw)
end
m = Model()
@variable(m, 1 <= x <= 2, MyVariable, category = :Bin, test_kw = 1, start = 3)
@test isa(x, MyVariable)
@test x.lowerbound == 1
@test x.upperbound == 2
@test x.category == :Bin
@test x.basename == "x"
@test x.start == 3
@test x.test_kw == 1
@variable(m, y[1:3] >= 0, MyVariable, test_kw = 2)
@test isa(y, Vector{MyVariable})
for i in 1:3
@test y[i].lowerbound == 0
@test y[i].upperbound == Inf
@test y[i].category == :Default
@test isempty(y[i].basename)
@test isnan(y[i].start)
@test y[i].test_kw == 2
end
end

@testset "constructconstraint! on variable" begin
m = Model()
@variable(m, x)
Expand Down
49 changes: 1 addition & 48 deletions test/variable.jl
Expand Up @@ -15,17 +15,8 @@ import JuMP.repl
using Base.Test

mutable struct MyVariable
haslb::Bool
lowerbound::Number
hasub::Bool
upperbound::Number
hasfix::Bool
fixedvalue::Number
binary::Bool
integer::Bool
info::JuMP.VariableInfo
name::String
hasstart::Bool
start::Number
test_kw::Int
end

Expand Down Expand Up @@ -326,44 +317,6 @@ end
@test JuMP.numvar(m) == 4
end

@testset "Extension of @variable with constructvariable! #1029" begin
JuMP.variabletype(m::Model, ::Type{MyVariable}) = MyVariable
function JuMP.constructvariable!(m::Model, ::Type{MyVariable}, _error::Function, args...; test_kw::Int = 0)
MyVariable(args..., test_kw)
end
m = Model()
@variable(m, 1 <= x <= 2, MyVariable, binary = true, test_kw = 1, start = 3)
@test isa(x, MyVariable)
@test x.haslb
@test x.lowerbound == 1
@test x.hasub
@test x.upperbound == 2
@test !x.hasfix
@test isnan(x.fixedvalue)
@test x.binary
@test !x.integer
@test x.name == "x"
@test x.hasstart
@test x.start == 3
@test x.test_kw == 1
@variable(m, y[1:3] >= 0, MyVariable, test_kw = 2)
@test isa(y, Vector{MyVariable})
for i in 1:3
@test y[i].haslb
@test y[i].lowerbound == 0
@test !y[i].hasub
@test y[i].upperbound == Inf
@test !y[i].hasfix
@test isnan(y[i].fixedvalue)
@test !y[i].binary
@test !y[i].integer
@test y[i].name == "y[$i]"
@test !y[i].hasstart
@test isnan(y[i].start)
@test y[i].test_kw == 2
end
end

# TODO decide what to do here
# @testset "getstart on sparse array (#889)" begin
# m = Model()
Expand Down

0 comments on commit 7e4a0d4

Please sign in to comment.