Skip to content

Commit

Permalink
Remove variable 'categories'
Browse files Browse the repository at this point in the history
  • Loading branch information
IainNZ committed Sep 3, 2015
1 parent c573363 commit 058f8df
Show file tree
Hide file tree
Showing 8 changed files with 66 additions and 60 deletions.
47 changes: 24 additions & 23 deletions src/JuMP.jl
Expand Up @@ -38,7 +38,7 @@ export
# Variable
setName, getName, setLower, setUpper, getLower, getUpper,
getValue, setValue, getDual, setCategory, getCategory,
getVar,
getVar, setType, getType,
getLinearIndex,
# Expressions and constraints
affToStr, quadToStr, exprToStr, conToStr, chgConstrRHS,
Expand Down Expand Up @@ -74,7 +74,7 @@ type Model
colNamesIJulia::Vector{UTF8String}
colLower::Vector{Float64}
colUpper::Vector{Float64}
colCat::Vector{Symbol}
colType::Vector{Symbol}

# Variable cones of the form, e.g. (:SDP, 1:9)
varCones::Vector{@compat Tuple{Symbol,Any}}
Expand Down Expand Up @@ -143,7 +143,7 @@ function Model(;solver=UnsetSolver())
UTF8String[], # colNamesIJulia
Float64[], # colLower
Float64[], # colUpper
Symbol[], # colCat
Symbol[], # colType
Vector{@compat Tuple{Symbol,Any}}[], # varCones
0, # objVal
Float64[], # colVal
Expand Down Expand Up @@ -240,7 +240,7 @@ function Base.copy(source::Model)
dest.colNamesIJulia = source.colNamesIJulia[:]
dest.colLower = source.colLower[:]
dest.colUpper = source.colUpper[:]
dest.colCat = source.colCat[:]
dest.colType = source.colType[:]

# varCones
dest.varCones = copy(source.varCones)
Expand Down Expand Up @@ -301,18 +301,18 @@ getLinearIndex(x::Variable) = x.col
ReverseDiffSparse.getplaceindex(x::Variable) = getLinearIndex(x)
Base.isequal(x::Variable,y::Variable) = (x.col == y.col) && (x.m === y.m)

Variable(m::Model, lower, upper, cat::Symbol, name::UTF8String="", value::Number=NaN) =
Variable(m::Model, lower, upper, vartype::Symbol, name::UTF8String="", value::Number=NaN) =
error("Attempt to create scalar Variable with lower bound of type $(typeof(lower)) and upper bound of type $(typeof(upper)). Bounds must be scalars in Variable constructor.")

function Variable(m::Model,lower::Number,upper::Number,cat::Symbol,name::UTF8String="",value::Number=NaN)
function Variable(m::Model,lower::Number,upper::Number,vartype::Symbol,name::UTF8String="",value::Number=NaN)
m.numCols += 1
push!(m.colNames, name)
push!(m.colNamesIJulia, name)
push!(m.colLower, convert(Float64,lower))
push!(m.colUpper, convert(Float64,upper))
push!(m.colCat, cat)
push!(m.colVal,value)
if cat == :Fixed
push!(m.colType, vartype)
push!(m.colVal, value)
if vartype == :Fixed
@assert lower == upper
m.colVal[end] = lower
end
Expand All @@ -337,11 +337,11 @@ getName(v::Variable) = var_str(REPLMode, v.m, v.col)

# Bound setter/getters
function setLower(v::Variable,lower::Number)
v.m.colCat[v.col] == :Fixed && error("use setValue for changing the value of a fixed variable")
v.m.colType[v.col] == :Fixed && error("use setValue for changing the value of a fixed variable")
v.m.colLower[v.col] = lower
end
function setUpper(v::Variable,upper::Number)
v.m.colCat[v.col] == :Fixed && error("use setValue for changing the value of a fixed variable")
v.m.colType[v.col] == :Fixed && error("use setValue for changing the value of a fixed variable")
v.m.colUpper[v.col] = upper
end
getLower(v::Variable) = v.m.colLower[v.col]
Expand All @@ -350,7 +350,7 @@ getUpper(v::Variable) = v.m.colUpper[v.col]
# Value setter/getter
function setValue(v::Variable, val::Number)
v.m.colVal[v.col] = val
if v.m.colCat[v.col] == :Fixed
if v.m.colType[v.col] == :Fixed
v.m.colLower[v.col] = val
v.m.colUpper[v.col] = val
end
Expand Down Expand Up @@ -416,12 +416,13 @@ function getDual(v::Variable)
end

const var_types = [:Cont, :Int, :Bin, :SemiCont, :SemiInt]
function setCategory(v::Variable, v_type::Symbol)
@Base.deprecate setCategory(v::Variable, v_type::Symbol) setType(v, v_type)
@Base.deprecate getCategory(v::Variable) getType(v)
function setType(v::Variable, v_type::Symbol)
v_type in var_types || error("Unrecognized variable type $v_type. Should be one of:\n $var_types")
v.m.colCat[v.col] = v_type
v.m.colType[v.col] = v_type
end

getCategory(v::Variable) = v.m.colCat[v.col]
getType(v::Variable) = v.m.colType[v.col]

Base.zero(::Type{Variable}) = AffExpr(Variable[],Float64[],0.0)
Base.zero(::Variable) = zero(Variable)
Expand Down Expand Up @@ -532,27 +533,27 @@ function chgConstrRHS(c::ConstraintRef{LinearConstraint}, rhs::Number)
end
end

Variable(m::Model,lower::Number,upper::Number,cat::Symbol,objcoef::Number,
Variable(m::Model,lower::Number,upper::Number,vartype::Symbol,objcoef::Number,
constraints::JuMPArray,coefficients::Vector{Float64}, name::String="", value::Number=NaN) =
Variable(m, lower, upper, cat, objcoef, constraints.innerArray, coefficients, name, value)
Variable(m, lower, upper, vartype, objcoef, constraints.innerArray, coefficients, name, value)

# add variable to existing constraints
function Variable(m::Model,lower::Number,upper::Number,cat::Symbol,objcoef::Number,
function Variable(m::Model,lower::Number,upper::Number,vartype::Symbol,objcoef::Number,
constraints::Vector,coefficients::Vector{Float64}, name::String="", value::Number=NaN)
for c in constraints
if !isa(c,ConstraintRef{LinearConstraint})
error("Unexpected constraint of type $(typeof(c)). Column-wise modeling only supported for linear constraints")
end
end
@assert cat != :Fixed || (lower == upper)
@assert vartype != :Fixed || (lower == upper)
m.numCols += 1
push!(m.colNames, name)
push!(m.colNamesIJulia, name)
push!(m.colLower, convert(Float64,lower))
push!(m.colUpper, convert(Float64,upper))
push!(m.colCat, cat)
push!(m.colVal,value)
if cat == :Fixed
push!(m.colType, vartype)
push!(m.colVal, value)
if vartype == :Fixed
@assert lower == upper
m.colVal[end] = lower
end
Expand Down
2 changes: 1 addition & 1 deletion src/nlp.jl
Expand Up @@ -539,7 +539,7 @@ function _buildInternalModel_nlp(m::Model, traits)

MathProgBase.loadnonlinearproblem!(m.internalModel, m.numCols, numConstr, m.colLower, m.colUpper, [linrowlb;quadrowlb;nlrowlb], [linrowub;quadrowub;nlrowub], m.objSense, d)
if traits.int
if applicable(MathProgBase.setvartype!, m.internalModel, m.colCat)
if applicable(MathProgBase.setvartype!, m.internalModel, m.colType)
MathProgBase.setvartype!(m.internalModel, vartypes_without_fixed(m))
else
error("Solver does not support discrete variables")
Expand Down
40 changes: 20 additions & 20 deletions src/print.jl
Expand Up @@ -132,10 +132,10 @@ function Base.show(io::IO, m::Model)
println(io, " * $(length(nlp.nlconstr)) nonlinear constraint$(plural(length(nlp.nlconstr)))")
end
print(io, " * $(m.numCols) variable$(plural(m.numCols))")
nbin = sum(m.colCat .== :Bin)
nint = sum(m.colCat .== :Int)
nsc = sum(m.colCat .== :SemiCont)
nsi = sum(m.colCat .== :SemiInt)
nbin = sum(m.colType .== :Bin)
nint = sum(m.colType .== :Int)
nsc = sum(m.colType .== :SemiCont)
nsi = sum(m.colType .== :SemiInt)
varstr = Any[]
nbin == 0 || push!(varstr, "$nbin binary")
nint == 0 || push!(varstr, "$nint integer")
Expand Down Expand Up @@ -196,10 +196,10 @@ function model_str(mode, m::Model, sym::PrintSymbols)
str *= sep * cont_str(mode,d,mathmode=true) * eol

# make sure that you haven't changed a variable type in the collection
cat = getCategory(first(_values(d)))
vartype = getType(first(_values(d)))
allsame = true
for v in _values(d)
if getCategory(v) != cat
if getType(v) != vartype
allsame = false
break
end
Expand All @@ -217,29 +217,29 @@ function model_str(mode, m::Model, sym::PrintSymbols)
var_name = var_str(mode,m,i)
var_lb, var_ub = m.colLower[i], m.colUpper[i]
str_lb, str_ub = str_round(var_lb), str_round(var_ub)
var_cat = m.colCat[i]
if var_cat == :Bin # x binary
vartype = m.colType[i]
if vartype == :Bin # x binary
str *= string(sep, var_name,
" ", sym[:in],
" ", sym[:open_set],
"0,1", sym[:close_set])
elseif var_cat == :SemiInt # x in union of 0 and {lb,...,ub}
elseif vartype == :SemiInt # x in union of 0 and {lb,...,ub}
str *= string(sep, var_name,
" ", sym[:in],
" ", sym[:open_set],
str_lb, sym[:mid_set], str_ub,
sym[:close_set],
" ", sym[:union], " ",
sym[:open_set], "0", sym[:close_set])
elseif var_cat == :SemiCont # x in union of 0 and [lb,ub]
elseif vartype == :SemiCont # x in union of 0 and [lb,ub]
str *= string(sep, var_name,
" ", sym[:in],
" ", sym[:open_rng],
str_lb, ",", str_ub,
sym[:close_rng],
" ", sym[:union], " ",
sym[:open_set], "0", sym[:close_set])
elseif var_cat == :Fixed
elseif vartype == :Fixed
str *= string(sep, var_name, " = ", str_lb)
elseif var_lb == -Inf && var_ub == +Inf # Free variable
str *= string(sep, var_name, " free")
Expand All @@ -252,7 +252,7 @@ function model_str(mode, m::Model, sym::PrintSymbols)
" ", var_name, " ",
sym[:leq], " ", str_ub)
end
if var_cat == :Int
if vartype == :Int
str *= string(", ", sym[:integer])
end
str *= eol
Expand Down Expand Up @@ -422,10 +422,10 @@ function cont_str(mode, j, sym::PrintSymbols)
idx_sets *= string(" s.t. ",join(parse_conditions(data.condition), " and "))
end

# 4. Bounds and category, if possible, and return final string
# 4. Bounds and type, if possible, and return final string
a_var = first(_values(j))
model = a_var.m
var_cat = model.colCat[a_var.col]
vartype = model.colType[a_var.col]
var_lb = model.colLower[a_var.col]
var_ub = model.colUpper[a_var.col]
# Variables may have different bounds, so we can't really print nicely
Expand All @@ -439,23 +439,23 @@ function cont_str(mode, j, sym::PrintSymbols)
end
str_lb = var_lb == -Inf ? "-"*sym[:infty] : str_round(var_lb)
str_ub = var_ub == +Inf ? sym[:infty] : str_round(var_ub)
# Special case bounds printing based on the category
if var_cat == :Bin # x in {0,1}
# Special case bounds printing based on the type
if vartype == :Bin # x in {0,1}
return "$name_idx $(sym[:in]) $(sym[:open_set])0,1$(sym[:close_set]) $idx_sets"
elseif var_cat == :SemiInt # x in union of 0 and {lb,...,ub}
elseif vartype == :SemiInt # x in union of 0 and {lb,...,ub}
si_lb = all_same_lb ? str_lb : ".."
si_ub = all_same_ub ? str_ub : ".."
return "$name_idx $(sym[:in]) $(sym[:open_set])$si_lb$(sym[:mid_set])$si_ub$(sym[:close_set]) $(sym[:union]) $(sym[:open_set])0$(sym[:close_set]) $idx_sets"
elseif var_cat == :SemiCont # x in union of 0 and [lb,ub]
elseif vartype == :SemiCont # x in union of 0 and [lb,ub]
si_lb = all_same_lb ? str_lb : ".."
si_ub = all_same_ub ? str_ub : ".."
return "$name_idx $(sym[:in]) $(sym[:open_rng])$si_lb,$si_ub$(sym[:close_rng]) $(sym[:union]) $(sym[:open_set])0$(sym[:close_set]) $idx_sets"
elseif var_cat == :Fixed
elseif vartype == :Fixed
si_bnd = all_same_lb ? str_lb : ".."
return "$name_idx = $si_bnd $idx_sets"
end
# Continuous and Integer
idx_sets = var_cat == :Int ? ", $(sym[:integer]), $idx_sets" : " $idx_sets"
idx_sets = vartype == :Int ? ", $(sym[:integer]), $idx_sets" : " $idx_sets"
if all_same_lb && all_same_ub
# Free variable
var_lb == -Inf && var_ub == +Inf && return "$name_idx free$idx_sets"
Expand Down
16 changes: 8 additions & 8 deletions src/solvers.jl
Expand Up @@ -27,7 +27,7 @@ immutable ProblemTraits
conic::Bool # has an SDP or SOC constraint
end
function ProblemTraits(m::Model)
int = any(c-> !(c == :Cont || c == :Fixed), m.colCat)
int = any(c-> !(c == :Cont || c == :Fixed), m.colType)
qp = !isempty(m.obj.qvars1)
qc = !isempty(m.quadconstr)
nlp = m.nlpdata !== nothing
Expand Down Expand Up @@ -261,8 +261,8 @@ function buildInternalModel(m::Model, traits=ProblemTraits(m);

# Update the type of each variable
if applicable(MathProgBase.setvartype!, m.internalModel, Symbol[])
colCats = vartypes_without_fixed(m)
MathProgBase.setvartype!(m.internalModel, colCats)
colTypes = vartypes_without_fixed(m)
MathProgBase.setvartype!(m.internalModel, colTypes)
elseif traits.int
# Solver that do not implement anything other than continuous
# variables do not need to implement this method, so throw an
Expand Down Expand Up @@ -469,14 +469,14 @@ function prepConstrMatrix(m::Model)
end

function vartypes_without_fixed(m::Model)
colCats = copy(m.colCat)
for i in 1:length(colCats)
if colCats[i] == :Fixed
colTypes = copy(m.colType)
for i in 1:length(colTypes)
if colTypes[i] == :Fixed
@assert m.colLower[i] == m.colUpper[i]
colCats[i] = :Cont
colTypes[i] = :Cont
end
end
return colCats
return colTypes
end

function collect_expr!(m, tmprow, terms::AffExpr)
Expand Down
4 changes: 2 additions & 2 deletions src/writers.jl
Expand Up @@ -47,7 +47,7 @@ function writeMPS(m::Model, fname::String)
inintegergroup = false
write(f,"COLUMNS\n")
for col in 1:m.numCols
t = m.colCat[col]
t = m.colType[col]
(t == :SemiCont || t == :SemiInt) && error("The MPS file writer does not currently support semicontinuous or semi-integer variables")
if (t == :Bin || t == :Int) && !inintegergroup
@printf(f," MARKER 'MARKER' 'INTORG'\n")
Expand Down Expand Up @@ -298,7 +298,7 @@ function writeLP(m::Model, fname::String)
# Integer - don't handle binaries specially
write(f,"General\n")
for i in 1:m.numCols
t = m.colCat[i]
t = m.colType[i]
(t == :SemiCont || t == :SemiInt) && error("The LP file writer does not currently support semicontinuous or semi-integer variables")
if t == :Bin || t == :Int
@printf(f, " VAR%d\n", i)
Expand Down
6 changes: 3 additions & 3 deletions test/print.jl
Expand Up @@ -418,13 +418,13 @@ Solver set to Default""", repl=:show)
""", repl=:print)
end

facts("[print] changing variable categories") do
facts("[print] changing variable types") do
le, ge = JuMP.repl[:leq], JuMP.repl[:geq]
mod = Model()
@defVar(mod, x[1:3])
@defVar(mod, y[i=1:3,i:3])
setCategory(x[3], :SemiCont)
setCategory(y[1,3], :Int)
setType(x[3], :SemiCont)
setType(y[1,3], :Int)

io_test(REPLMode, mod, """
Min 0
Expand Down
2 changes: 1 addition & 1 deletion test/probmod.jl
Expand Up @@ -95,7 +95,7 @@ context("With solver $(typeof(solver))") do
# 0 <= z <= 1.5, Integer
# x* = 2, y* = 0, z* = 1
setUpper(z, 1.5)
m.colCat[3] = :Int
setType(z, :Int)
@fact solve(m) --> :Optimal
@fact getValue(x) --> roughly(2.0, TOL)
@fact getValue(y) --> roughly(0.0, TOL)
Expand Down
9 changes: 7 additions & 2 deletions test/variable.jl
Expand Up @@ -81,12 +81,17 @@ facts("[variable] get and set values") do
end
end

facts("[variable] get and set category") do
facts("[variable] get and set type") do
m = Model()
@defVar(m, x[1:3])
setCategory(x[2], :Int)
@fact getCategory(x[3]) --> :Cont
@fact getCategory(x[1]) --> :Cont
@fact getCategory(x[2]) --> :Int
@fact getCategory(x[3]) --> :Cont
setType(x[1], :Int)
@fact getType(x[1]) --> :Int
@fact getType(x[2]) --> :Int
@fact getType(x[3]) --> :Cont
end

facts("[variable] repeated elements in index set (issue #199)") do
Expand Down

0 comments on commit 058f8df

Please sign in to comment.