Containers

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.

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
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.

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:

  1. If all index sets are either explicit 1:B objects for any B or symbols which refer to objects of type Base.OneTo, then an Array 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 the Base.OneTo condition.

  2. 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.

  3. 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:

Each expression index_set_i can either be

The macro then creates the container using the JuMP.Containers.generate_container function with the following arguments:

  1. VariableRef for the @variable macro and ConstraintRef for the @constraint macro.
  2. The index variables and arbitrary symbols for dimensions for which no variable index is specified.
  3. The index sets specified.
  4. The value of the keyword argument if given or :Auto.