Containers
JuMP provides a specialized container similar to AxisArrays
that enables indexing with non-integer indices. Normally these are created automatically by JuMP's macros. The following constructors can be used to create them manually.
JuMP.Containers.DenseAxisArray
— Type.DenseAxisArray(data::Array{T, N}, axes...) where {T, N}
Construct a JuMP array with the underlying data specified by the data
array and the given axes. Exactly N
axes must be provided, and their lengths must match size(data)
in the corresponding dimensions.
Example
julia> array = JuMP.Containers.DenseAxisArray([1 2; 3 4], [:a, :b], 2:3)
2-dimensional DenseAxisArray{Int64,2,...} with index sets:
Dimension 1, Symbol[:a, :b]
Dimension 2, 2:3
And data, a 2×2 Array{Int64,2}:
1 2
3 4
julia> array[:b, 3]
4
DenseAxisArray{T}(undef, axes...) where T
Construct an uninitialized DenseAxisArray with element-type T
indexed over the given axes.
Example
julia> array = JuMP.Containers.DenseAxisArray{Float64}(undef, [:a, :b], 1:2);
julia> fill!(array, 1.0)
2-dimensional DenseAxisArray{Float64,2,...} with index sets:
Dimension 1, Symbol[:a, :b]
Dimension 2, 1:2
And data, a 2×2 Array{Float64,2}:
1.0 1.0
1.0 1.0
julia> array[:a, 2] = 5.0
5.0
julia> array[:a, 2]
5.0
julia> array
2-dimensional DenseAxisArray{Float64,2,...} with index sets:
Dimension 1, Symbol[:a, :b]
Dimension 2, 1:2
And data, a 2×2 Array{Float64,2}:
1.0 5.0
1.0 1.0
JuMP.Containers.SparseAxisArray
— Type.struct SparseAxisArray{T,N,K<:NTuple{N, Any}} <: AbstractArray{T,N}
data::Dict{K,T}
end
N
-dimensional array with elements of type T
where only a subset of the entries are defined. The entries with indices idx = (i1, i2, ..., iN)
in keys(data)
has value data[idx]
. Note that as opposed to SparseArrays.AbstractSparseArray
, the missing entries are not assumed to be zero(T)
, they are simply not part of the array. This means that the result of map(f, sa::SparseAxisArray)
or f.(sa::SparseAxisArray)
has the same sparsity structure than sa
even if f(zero(T))
is not zero.
Example
julia> dict = Dict((:a, 2) => 1.0, (:a, 3) => 2.0, (:b, 3) => 3.0)
Dict{Tuple{Symbol,Int64},Float64} with 3 entries:
(:b, 3) => 3.0
(:a, 2) => 1.0
(:a, 3) => 2.0
julia> array = JuMP.Containers.SparseAxisArray(dict)
JuMP.Containers.SparseAxisArray{Float64,2,Tuple{Symbol,Int64}} with 3 entries:
[b, 3] = 3.0
[a, 2] = 1.0
[a, 3] = 2.0
julia> array[:b, 3]
3.0
Containers in macros
The generate_container
function encodes the logic for how containers are constructed in JuMP's macros.
JuMP.Containers.generate_container
— Function.generate_container(T, indexvars, indexsets, requestedtype)
Return a tuple, the first element of which is code that generates a container for objects of type T
given the index variables, index sets, and requestedtype
. requestedtype
may be one of :Array
, :DenseAxisArray
, :SparseAxisArray
, or :Auto
. Return error-producing code if requested type is incompatible. For the case of :Auto
, the following rules are used to determine the appropriate container:
If all index sets are either explicit
1:B
objects for anyB
or symbols which refer to objects of typeBase.OneTo
, then anArray
is generated of the appropriate size. Types of symbols/expressions are not known at compile time, so we defer to type-safe functions to check theBase.OneTo
condition.If condition (1) does not hold, and the index sets are independent (the index variable for one set does not appear in the definition of another), then an
DenseAxisArray
is generated of the appropriate size.Otherwise, generate an empty
SparseAxisArray{T,N,NTuple{N,Any}}
.
The second element of the return tuple is a Bool
, true
if the container type automatically checks for duplicate terms in the index sets and false
otherwise.
Examples
generate_container(VariableRef, [:i,:j], [:(1:N), :(1:T)], :Auto)
# Returns code equivalent to:
# :(Array{VariableRef}(length(1:N), length(1:T))
generate_container(VariableRef, [:i,:j], [:(1:N), :(2:T)], :Auto)
# Returns code equivalent to:
# :(JuMP.Containers.DenseAxisArray(undef, 1:N, 2:T))
generate_container(VariableRef, [:i,:j], [:(1:N), :(S)], :Auto)
# Returns code that generates an Array if S is of type Base.OneTo,
# otherwise an DenseAxisArray.
generate_container(VariableRef, [:i,:j], [:(1:N), :(1:j)], :Auto)
# Returns code equivalent to:
# :(Containers.SparseAxisArray(Dict{NTuple{N,Any},VariableRef}()))
In the @variable
(resp. @constraint
) macro, containers of variables (resp. constraints) can be created with the following syntax:
name[index_set_1, index_set_2, ..., index_set_n]
creating ann
-dimensional container of namename
; or[index_set_1, index_set_2, ..., index_set_n]
creating an anonymousn
-dimensional container.
Each expression index_set_i
can either be
- of the form
index_set
specifying that thei
th index set of the container isindex_set
; or - of the form
index_name=index_set
specifying that thei
th index set of the container isindex_set
and allowing values used in the macro expression and keyword arguments to be expressions depending on theindex_name
.
The macro then creates the container using the JuMP.Containers.generate_container
function with the following arguments:
VariableRef
for the@variable
macro andConstraintRef
for the@constraint
macro.- The index variables and arbitrary symbols for dimensions for which no variable index is specified.
- The index sets specified.
- The value of the
keyword
argument if given or:Auto
.