Skip to content

Commit

Permalink
O̶n̶e̶I̶n̶d̶e̶x̶e̶d̶A̶r̶r̶a̶y̶
Browse files Browse the repository at this point in the history
  • Loading branch information
joehuchette committed Aug 25, 2015
1 parent 7939a0b commit 50f0da3
Show file tree
Hide file tree
Showing 18 changed files with 390 additions and 502 deletions.
4 changes: 2 additions & 2 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@ Unversioned
-----------

* Support (on Julia 0.4 and later) for conditions in indexing ``@defVar`` and ``@addConstraint`` constructs, e.g. ``@defVar(m, x[i=1:5,j=1:5; i+j >= 3])``
* Support for vectorized operations on Variables, expressions, and JuMPArrays with indexing over unit-step ranges starting at one. See
the documentation for details.
* Support for vectorized operations on Variables and expressions. See the documentation for details.
* New ``getVar()`` method to access variables in a model by name
* Support for semidefinite programming.
* Dual solutions are now available for general nonlinear problems. You may call ``getDual`` on a reference object for a nonlinear constraint, and ``getDual`` on a variable object for Lagrange multipliers from active bounds.
* Introduce warnings for two common performance traps: too many calls to ``getValue()`` on a collection of variables and use of the ``+`` operator in a loop to sum expressions.
* Second-order cone constraints can be written directly with the ``norm()`` and ``norm2{}`` syntax.
* Implement MathProgBase interface for querying Hessian-vector products.
* Iteration over ``JuMPContainer``s is deprecated; instead, use the ``keys`` and ``values`` functions, and ``zip(keys(d),values(d))`` for the old behavior.
* ``@defVar`` returns ``Array{Variable,N}`` when each of ``N`` index sets are of the form ``1:nᵢ``.

Version 0.9.3 (August 11, 2015)
-------------------------------
Expand Down
16 changes: 8 additions & 8 deletions doc/refexpr.rst
Original file line number Diff line number Diff line change
Expand Up @@ -139,16 +139,16 @@ Vectorized operations
^^^^^^^^^^^^^^^^^^^^^

JuMP supports vectorized expressions and constraints for linear and quadratic models. Although this syntax may
be familiar for users coming from MATLAB-based modeling languages, we caution that this syntax can be slow---especially
for large operations. Nevertheless, the syntax often proves useful, for example in constraints involving small,
dense matrix-vector products.
be familiar for users coming from MATLAB-based modeling languages, we caution that this syntax may be slower than
the scalar versions using loops---especially for large operations. Nevertheless, the syntax often proves useful,
for example in constraints involving small, dense matrix-vector products.

Linear algebraic operators are available to give meaning to expressions like ``A*x`` where ``A`` is a matrix
of numbers and ``x`` is a vector of ``Variable``s. You may also use ``JuMPArray``s in these types of expressions,
but only if the index sets that define them are matrix-like: that is, the index sets are ranges of the type
of numbers and ``x`` is a vector of ``Variable``s. You may also use ``Array{Variable}``s in these types of
expressions; for example, any object you construct with ``@defVar`` where each of the index sets are of the form
``1:n``. For example::

@defVar(m, x[1:3])
@defVar(m, x[1:3,1:4])
expr = rand(3,3)*x

is allowed, while::
Expand All @@ -169,8 +169,8 @@ and ``.<=``. For instance, you can write constraints of the form::

Note that scalar literals (such as 1 or 0) are allowed in expressions.

Concatenation is also overloaded for these matrix-like ``JuMPArray``s. For instance, the following will create
a matrix of ``QuadExpr`` that you can use elsewhere in your model::
Concatenation is also possible for these ``Array``s of ``Variable``s or expressions. For instance, the following
will create a matrix of ``QuadExpr`` that you can use elsewhere in your model::

@defVar(m, x[1:3])
A = [1 x'
Expand Down
124 changes: 76 additions & 48 deletions src/JuMP.jl
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,9 @@ type Model
colUpper::Vector{Float64}
colCat::Vector{Symbol}

# Variable cones of the form, e.g. (:SDP, 1:9)
varCones::Vector{@compat Tuple{Symbol,Any}}

# Solution data
objVal
colVal::Vector{Float64}
Expand Down Expand Up @@ -107,6 +110,7 @@ type Model
nlpdata#::NLPData

varDict::Dict{Symbol,Any} # dictionary from variable names to variable objects
varData::ObjectIdDict

getvalue_counter::Int # number of times we call getValue on a JuMPContainer, so that we can print out a warning
operator_counter::Int # number of times we add large expressions
Expand All @@ -127,36 +131,38 @@ function Model(;solver=UnsetSolver())
if !isa(solver,MathProgBase.AbstractMathProgSolver)
error("solver argument ($solver) must be an AbstractMathProgSolver")
end
Model(zero(QuadExpr), # obj
:Min, # objSense
LinearConstraint[], # linconstr
QuadConstraint[], # quadconstr
SOSConstraint[], # sosconstr
SOCConstraint[], # socconstr
SDPConstraint[], # sdpconstr
0, # numCols
UTF8String[], # colNames
UTF8String[], # colNamesIJulia
Float64[], # colLower
Float64[], # colUpper
Symbol[], # colCat
0, # objVal
Float64[], # colVal
Float64[], # redCosts
Float64[], # linconstrDuals
nothing, # internalModel
solver, # solver
false, # internalModelLoaded
Any[], # callbacks
nothing, # solvehook
nothing, # printhook
JuMPContainer[], # dictList
IndexedVector(Float64,0), # indexedVector
nothing, # nlpdata
Dict{Symbol,Any}(), # varDict
0, # getvalue_counter
0, # operator_counter
Dict{Symbol,Any}(), # ext
Model(zero(QuadExpr), # obj
:Min, # objSense
LinearConstraint[], # linconstr
QuadConstraint[], # quadconstr
SOSConstraint[], # sosconstr
SOCConstraint[], # socconstr
SDPConstraint[], # sdpconstr
0, # numCols
UTF8String[], # colNames
UTF8String[], # colNamesIJulia
Float64[], # colLower
Float64[], # colUpper
Symbol[], # colCat
Vector{@compat Tuple{Symbol,Any}}[], # varCones
0, # objVal
Float64[], # colVal
Float64[], # redCosts
Float64[], # linconstrDuals
nothing, # internalModel
solver, # solver
false, # internalModelLoaded
Any[], # callbacks
nothing, # solvehook
nothing, # printhook
Any[], # dictList
IndexedVector(Float64,0), # indexedVector
nothing, # nlpdata
Dict{Symbol,Any}(), # varDict
ObjectIdDict(), # varData
0, # getvalue_counter
0, # operator_counter
Dict{Symbol,Any}(), # ext
)
end

Expand Down Expand Up @@ -236,6 +242,9 @@ function Base.copy(source::Model)
dest.colUpper = source.colUpper[:]
dest.colCat = source.colCat[:]

# varCones
dest.varCones = copy(source.varCones)

# callbacks and hooks
if !isempty(source.callbacks)
error("Copying callbacks is not supported")
Expand All @@ -255,7 +264,8 @@ function Base.copy(source::Model)
for (symb,v) in source.varDict
dest.varDict[symb] = copy(v, dest)
end
dest.dictList = map(v -> copy(v, dest), source.dictList)

# varData---possibly shouldn't copy

if source.nlpdata !== nothing
dest.nlpdata = copy(source.nlpdata)
Expand Down Expand Up @@ -357,7 +367,30 @@ function getValue(v::Variable)
ret
end

getValue(arr::Array{Variable}) = map(getValue, arr)
function getValue(arr::Array{Variable})
ret = similar(arr, Float64)
if isempty(ret)
return ret
end
warnedyet = false
m = first(arr).m
# whether this was constructed via @defVar, essentially
registered = haskey(m.varData, arr)
name = registered ? m.varData[arr].name : m.colName[v.col]
for I in eachindex(arr)
v = arr[I]
value = _getValue(v)
ret[I] = value
if !warnedyet && isnan(value)
Base.warn("Variable value not defined for $name. Check that the model was properly solved.")
warnedyet = true
end
end
if registered
m.varData[ret] = m.varData[arr]
end
ret
end

# Dual value (reduced cost) getter
function getDual(v::Variable)
Expand Down Expand Up @@ -389,19 +422,17 @@ function verify_ownership(m::Model, vec::Vector{Variable})
end

Base.copy(v::Variable, new_model::Model) = Variable(new_model, v.col)
function Base.copy(v::Array{Variable}, new_model::Model)
ret = similar(v, Variable, size(v))
for I in eachindex(v)
ret[I] = Variable(new_model, v[I].col)
end
ret
end

# Copy methods for variable containers
Base.copy(d::JuMPContainer) = map(copy, d)
Base.copy(d::JuMPContainer, new_model::Model) = map(x -> copy(x, new_model), d)
Base.copy{T<:OneIndexedArray}(d::T) = T(map(copy, d.innerArray),
d.name,
d.indexsets,
d.indexexprs)
Base.copy{T<:OneIndexedArray}(d::T, new_model::Model) =
T(map(v -> copy(v, new_model), d.innerArray),
d.name,
d.indexsets,
d.indexexprs)

###############################################################################
# Generic affine expression class
Expand Down Expand Up @@ -465,7 +496,9 @@ end
typealias AffExpr GenericAffExpr{Float64,Variable}

AffExpr() = zero(AffExpr)
# TODO: remove these when no longer supporting v0.3
AffExpr(x::Union(Number,Variable)) = convert(AffExpr, x)
AffExpr(x::AffExpr) = x

Base.isempty(a::AffExpr) = (length(a.vars) == 0 && a.constant == 0.)
Base.convert(::Type{AffExpr}, v::Variable) = AffExpr([v], [1.], 0.)
Expand Down Expand Up @@ -582,11 +615,11 @@ end
# scalars, and Xᵢ are n×n symmetric variable matrices. The inequality
# is taken w.r.t. the psd partial order.
type SDPConstraint <: JuMPConstraint
terms # purposely leave this untyped so that we can special-case OneIndexedArray with no additional variables
terms
end

# Special-case X ≥ 0, which is often convenient
function SDPConstraint(lhs::Union(OneIndexedArray,Matrix), rhs::Number)
function SDPConstraint(lhs::Matrix, rhs::Number)
rhs == 0 || error("Cannot construct a semidefinite constraint with nonzero scalar bound $rhs")
SDPConstraint(lhs)
end
Expand Down Expand Up @@ -753,11 +786,6 @@ Base.ndims(::JuMPTypes) = 0
##########################################################################
# Operator overloads
include("operators.jl")
if VERSION > v"0.4-"
include(joinpath("v0.4","concatenation.jl"))
else
include(joinpath("v0.3","concatenation.jl"))
end
# Writers - we support MPS (MILP + QuadObj), LP (MILP)
include("writers.jl")
# Macros - @defVar, sum{}, etc.
Expand Down
Loading

0 comments on commit 50f0da3

Please sign in to comment.