Документация Engee

Справка по API контейнеров

Containers

Модуль, в котором определены контейнеры DenseAxisArray и SparseAxisArray, подобные обычным массивам AbstractArray, но с пользовательскими индексами, которые не обязательно являются целыми числами.

AutoContainerType

Передайте AutoContainerType в container, чтобы тип контейнера выбирался на основе типа индексов с использованием default_container.

DenseAxisArray(data::Array{T, N}, axes...) where {T, N}

Создает массив JuMP с базовыми данными, указанными в массиве data, и заданными осями. Необходимо передать ровно N осей, а их длины должны соответствовать size(data) в соответствующих измерениях.

Пример

julia> array = Containers.DenseAxisArray([1 2; 3 4], [:a, :b], 2:3)
2-dimensional DenseAxisArray{Int64,2,...} with index sets:
    Dimension 1, [:a, :b]
    Dimension 2, 2:3
And data, a 2×2 Matrix{Int64}:
 1  2
 3  4

julia> array[:b, 3]
4
DenseAxisArray{T}(undef, axes...) where T

Создает неинициализированный массив DenseAxisArray с типом элементов T, индексируемый по заданным осям.

Пример

julia> array = Containers.DenseAxisArray{Float64}(undef, [:a, :b], 1:2);

julia> fill!(array, 1.0)
2-dimensional DenseAxisArray{Float64,2,...} with index sets:
    Dimension 1, [:a, :b]
    Dimension 2, 1:2
And data, a 2×2 Matrix{Float64}:
 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, [:a, :b]
    Dimension 2, 1:2
And data, a 2×2 Matrix{Float64}:
 1.0  5.0
 1.0  1.0
DenseAxisArrayKey

Структура для хранения ключа DenseAxisArray, когда он рассматривается как коллекция ключей и значений.

struct NestedIterator{T}
    iterators::T # Tuple of functions
    condition::Function
end

Итераторы по кортежам, создаваемым вложенным циклом for.

Итератор NestedIterator создается с помощью nested.

Пример

julia> iterators = (() -> 1:2, (i,) -> ["A", "B"]);

julia> condition = (i, j) -> isodd(i) || j == "B";

julia> x = Containers.NestedIterator(iterators, condition);

julia> for (i, j) in x
           println((i, j))
       end
(1, "A")
(1, "B")
(2, "B")

равносильно

julia> for i in iterators[1]()
           for j in iterators[2](i)
               if condition(i, j)
                   println((i, j))
               end
           end
       end
(1, "A")
(1, "B")
(2, "B")
struct NoDuplicateDict{K, V} <: AbstractDict{K, V}
    dict::OrderedCollections.OrderedDict{K, V}
end

Действует аналогично OrderedCollections.OrderedDict{K, V}, но выдает ошибку при создании на основе итератора с повторяющимися ключами.

struct SparseAxisArray{T,N,K<:NTuple{N, Any}} <: AbstractArray{T,N}
    data::OrderedCollections.OrderedDict{K,T}
end

N-мерный массив с элементами типа T, в котором определено лишь подмножество элементов. Элементы с индексами idx = (i1, i2, ..., iN) в keys(data) имеют значение data[idx].

Обратите внимание, что, в отличие от SparseArrays.AbstractSparseArray, отсутствующие элементы не считаются zero(T); они просто не входят в массив. Это означает, что результат вызова map(f, sa::SparseAxisArray) или f.(sa::SparseAxisArray) имеет ту же структуру разреженности, что и sa, даже если f(zero(T)) не равно нулю.

Пример

julia> using OrderedCollections: OrderedDict

julia> dict = OrderedDict((:a, 2) => 1.0, (:a, 3) => 2.0, (:b, 3) => 3.0)
OrderedDict{Tuple{Symbol, Int64}, Float64} with 3 entries:
  (:a, 2) => 1.0
  (:a, 3) => 2.0
  (:b, 3) => 3.0

julia> array = Containers.SparseAxisArray(dict)
SparseAxisArray{Float64, 2, Tuple{Symbol, Int64}} with 3 entries:
  [a, 2]  =  1.0
  [a, 3]  =  2.0
  [b, 3]  =  3.0

julia> array[:b, 3]
3.0
struct VectorizedProductIterator{T}
    prod::Iterators.ProductIterator{T}
end

Тип-оболочка для Iterators.ProuctIterator, который игнорирует информацию о форме и возвращает Vector.

Итератор VectorizedProductIterator создается с помощью vectorized_product.

_explicit_oneto(error_fn, index_set)

Если index_set соответствует форме 1:N, возвращается Base.OneTo(index_set).

_expr_is_splat(expr)

Возвращает значение true, если expr — это выражение ... (или esc).

_extract_kw_args(args)

Эта функция является нерекомендуемой. Используйте вместо нее parse_macro_arguments.

_get_arg(args::Tuple, index::Tuple)

Возвращает кортеж, который соответствует tuple([arg[index] for arg in args]...), но стабилен по типу.

_parse_ref_sets(expr::Expr)

Вспомогательная функция для макросов, позволяющая создавать объекты-контейнеры.

Принимает выражение Expr, которое определяет контейнер, например :(x[i=1:3,[:red,:blue],k=S; i+k <= 6]), и возвращает следующие значения:

  1. index_vars: имена переменных индексов, например [:i, gensym(), :k].

Это также могут быть выражения, например :i, j из такого вызова, как :(x[(i, j) in S]).

  1. index_sets: множества, используемые для индексирования, например [1:3, [:red,:blue], S].

  2. condition: выражение, содержащее все условия, налагаемые на индексирование, или :(),

если таковых нет.

add_additional_args(
    call::Expr,
    args::Vector,
    kwargs::Dict{Symbol,Any};
    kwarg_exclude::Vector{Symbol} = Symbol[],
)

Добавляет позиционные аргументы args в выражение вызова функции call, экранируя каждое выражение аргумента.

Эта функция может включать дополнительные позиционные аргументы для вызовов call, которые уже содержат именованные аргументы.

build_error_fn(macro_name, args, source)

Возвращает функцию, которую можно использовать вместо Base.error, но которая дополнительно выводит макрос, из которого она была вызвана.

build_name_expr(
    name::Union{Symbol,Nothing},
    index_vars::Vector,
    kwargs::Dict{Symbol,Any},
)

Возвращает выражение для имени элемента контейнера, где name и index_vars — значения, возвращаемые parse_ref_sets, а kwargs — словарь, возвращаемый parse_macro_arguments.

Предполагается, что ключ в kwargs, используемый для переопределения выбранного имени, — это :base_name.

Пример

julia> Containers.build_name_expr(:x, [:i, :j], Dict{Symbol,Any}())
:(string("x", "[", string($(Expr(:escape, :i))), ",", string($(Expr(:escape, :j))), "]"))

julia> Containers.build_name_expr(nothing, [:i, :j], Dict{Symbol,Any}())
""

julia> Containers.build_name_expr(:y, [:i, :j], Dict{Symbol,Any}(:base_name => "y"))
:(string("y", "[", string($(Expr(:escape, :i))), ",", string($(Expr(:escape, :j))), "]"))
build_ref_sets(error_fn::Function, expr)

Эта функция является нерекомендуемой. Используйте вместо нее parse_ref_sets.

container(f::Function, indices[[, ::Type{C} = AutoContainerType], names])

Создает контейнер типа C с именами индексов names, индексами indices и значениями по индексам, определяемыми функцией f.

Если метод с names не специализирован для Type{C}, по умолчанию вызывается container(f, indices, c) для обратной совместимости с контейнерами, не поддерживающими имена индексов.

Пример

julia> Containers.container((i, j) -> i + j, Containers.vectorized_product(Base.OneTo(3), Base.OneTo(3)))
3×3 Matrix{Int64}:
 2  3  4
 3  4  5
 4  5  6

julia> Containers.container((i, j) -> i + j, Containers.vectorized_product(1:3, 1:3))
2-dimensional DenseAxisArray{Int64,2,...} with index sets:
    Dimension 1, 1:3
    Dimension 2, 1:3
And data, a 3×3 Matrix{Int64}:
 2  3  4
 3  4  5
 4  5  6

julia> Containers.container((i, j) -> i + j, Containers.vectorized_product(2:3, Base.OneTo(3)))
2-dimensional DenseAxisArray{Int64,2,...} with index sets:
    Dimension 1, 2:3
    Dimension 2, Base.OneTo(3)
And data, a 2×3 Matrix{Int64}:
 3  4  5
 4  5  6

julia> Containers.container((i, j) -> i + j, Containers.nested(() -> 1:3, i -> i:3, condition = (i, j) -> isodd(i) || isodd(j)))
SparseAxisArray{Int64, 2, Tuple{Int64, Int64}} with 5 entries:
  [1, 1]  =  2
  [1, 2]  =  3
  [1, 3]  =  4
  [2, 3]  =  5
  [3, 3]  =  6
container_code(
    index_vars::Vector{Any},
    indices::Expr,
    code,
    requested_container::Union{Symbol,Expr,Dict{Symbol,Any}},
)

Используется в макросах для построения вызова container. Следует использовать в сочетании с parse_ref_sets.

Аргументы

  • index_vars::Vector{Any}: вектор имен индексов контейнера. Это также могут быть выражения, например :i, j из такого вызова, как :(x[(i, j) in S]).

  • indices::Expr: выражение, результатом вычисления которого является итератор индексов.

  • code: выражение или литеральная константа для значения, которое будет сохранено в контейнере как функция именованного index_vars.

  • requested_container: передается в третьем аргументе container. Для встроенных типов JuMP выберите :Array, :DenseAxisArray, :SparseAxisArray или :Auto. Для пользовательского контейнера результат вычисления этого выражения должен иметь правильный тип. Можно также передать словарь kwargs из parse_macro_arguments.

В большинстве случаев перед передачей кода в container_code его следует экранировать (esc(code)).

Пример

julia> macro foo(ref_sets, code)
           name, index_vars, indices =
               Containers.parse_ref_sets(error, ref_sets)
           @assert name !== nothing  # Анонимный контейнер не поддерживается
           container =
               Containers.container_code(index_vars, indices, esc(code), :Auto)
           return quote
               $(esc(name)) = $container
           end
       end
@foo (macro with 1 method)

julia> @foo(x[i=1:2, j=["A", "B"]], j^i);

julia> x
2-dimensional DenseAxisArray{String,2,...} with index sets:
    Dimension 1, Base.OneTo(2)
    Dimension 2, ["A", "B"]
And data, a 2×2 Matrix{String}:
 "A"   "B"
 "AA"  "BB"
default_container(indices)

Если indices — это объект NestedIterator, возвращает SparseAxisArray. В противном случае indices должно быть объектом VectorizedProductIterator, и эта функция возвращает Array, если все итераторы произведения равны Base.OneTo, или DenseAxisArray в противном случае.

nested(iterators...; condition = (args...) -> true)

Создает объект NestedIterator.

Пример

julia> iterator = Containers.nested(
           () -> 1:2,
           (i,) -> ["A", "B"];
           condition = (i, j) -> isodd(i) || j == "B",
       );

julia> collect(iterator)
3-element Vector{Tuple{Int64, String}}:
 (1, "A")
 (1, "B")
 (2, "B")
parse_macro_arguments(
    error_fn::Function,
    args;
    valid_kwargs::Union{Nothing,Vector{Symbol}} = nothing,
    num_positional_args::Union{Nothing,Int,UnitRange{Int}} = nothing,
)

Возвращает кортеж Tuple{Vector{Any},Dict{Symbol,Any}}, содержащий упорядоченные позиционные аргументы и словарь, в котором сопоставляются именованные аргументы.

В частности, служит для различения @foo(key = value) и @foo(; key = value) в макросах.

При передаче нескольких именованных аргументов с одинаковым ключом выдается ошибка.

Если valid_kwargs — это объект Vector{Symbol}, при отсутствии именованного аргумента в valid_kwargs выдается ошибка.

Если значение num_positional_args отлично от nothing, при отсутствии числа позиционных аргументов в num_positional_args выдается ошибка.

parse_ref_sets(
    error_fn::Function,
    expr;
    invalid_index_variables::Vector{Symbol} = Symbol[],
)

Вспомогательная функция для макросов, позволяющая создавать объекты-контейнеры.

Эта функция предназначена для опытных пользователей, реализующих расширения JuMP. Дополнительные сведения см. в описании метода container_code.

Аргументы

  • error_fn: функция, которая принимает String и выдает ошибку; входная строка может быть аннотирована дополнительной информацией, например именем макроса, из которого была выдана ошибка. Чтобы не изменять сообщение об ошибке, используйте error.

  • expr: выражение Expr, которое определяет контейнер, например :(x[i = 1:3, [:red, :blue], k = S; i + k <= 6]).

Возвращаемые значения

  1. name: имя контейнера, если оно задано; в противном случае nothing.

  2. index_vars: вектор Vector{Any} имен переменных индексов, например

[:i, gensym(), :k]. Это также могут быть выражения, например :i, j из такого вызова, как :(x[(i, j) in S]).

  1. indices: итератор по индексам, например

Пример

Рабочий пример см. в описании метода container_code.

rowtable([f::Function=identity,] x; [header::Vector{Symbol} = Symbol[]])

Применяет функцию f ко всем элементам контейнера переменных x, возвращая результат в виде вектора Vector кортежей NamedTuple, где header — это вектор с соответствующими именами осей.

Если x — это N-мерный массив, то имен должно быть N+1, чтобы последнее имя соответствовало результату f(x[i]).

Если аргумент header пустой, то заголовок по умолчанию будет [:x1, :x2, ..., :xN, :y].

Вектор Vector кортежей NamedTuple реализует интерфейс Tables.jl, поэтому результат можно использовать в качестве входных данных любой функции, которая поддерживает совместимый с Tables.jl источник данных.

Пример

julia> model = Model();

julia> @variable(model, x[i=1:2, j=i:2] >= 0, start = i+j);

julia> Containers.rowtable(start_value, x; header = [:i, :j, :start])
3-element Vector{@NamedTuple{i::Int64, j::Int64, start::Float64}}:
 (i = 1, j = 1, start = 2.0)
 (i = 1, j = 2, start = 3.0)
 (i = 2, j = 2, start = 4.0)

julia> Containers.rowtable(x)
3-element Vector{@NamedTuple{x1::Int64, x2::Int64, y::VariableRef}}:
 (x1 = 1, x2 = 1, y = x[1,1])
 (x1 = 1, x2 = 2, y = x[1,2])
 (x1 = 2, x2 = 2, y = x[2,2])
vectorized_product(iterators...)

Создает объект VectorizedProductIterator.

Пример

julia> iterator = Containers.vectorized_product(1:2, ["A", "B"]);

julia> collect(iterator)
2×2 Matrix{Tuple{Int64, String}}:
 (1, "A")  (1, "B")
 (2, "A")  (2, "B")
@container([i=..., j=..., ...], expr[, container = :Auto])

Создает контейнер с индексами i, j, …​ и значениями, задаваемыми выражением expr, которые могут зависеть от значения индексов.

@container(ref[i=..., j=..., ...], expr[, container = :Auto])

То же, что и выше, но контейнер присваивается переменной с именем ref.

Типом контейнера можно управлять с помощью именованного аргумента container.

Когда множество индексов явно задано как 1:n для любого выражения n, перед передачей в container оно преобразовывается в Base.OneTo(n).

Пример

julia> Containers.@container([i = 1:3, j = 1:3], i + j)
3×3 Matrix{Int64}:
 2  3  4
 3  4  5
 4  5  6

julia> I = 1:3
1:3

julia> Containers.@container(x[i = I, j = I], i + j);

julia> x
2-dimensional DenseAxisArray{Int64,2,...} with index sets:
    Dimension 1, 1:3
    Dimension 2, 1:3
And data, a 3×3 Matrix{Int64}:
 2  3  4
 3  4  5
 4  5  6

julia> Containers.@container([i = 2:3, j = 1:3], i + j)
2-dimensional DenseAxisArray{Int64,2,...} with index sets:
    Dimension 1, 2:3
    Dimension 2, Base.OneTo(3)
And data, a 2×3 Matrix{Int64}:
 3  4  5
 4  5  6

julia> Containers.@container([i = 1:3, j = 1:3; i <= j], i + j)
SparseAxisArray{Int64, 2, Tuple{Int64, Int64}} with 6 entries:
  [1, 1]  =  2
  [1, 2]  =  3
  [1, 3]  =  4
  [2, 2]  =  4
  [2, 3]  =  5
  [3, 3]  =  6