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

Выражения

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

Аффинные выражения

В JuMP аффинные выражения можно создавать четырьмя способами: с помощью макроса @expression, путем перегрузки операторов, с помощью конструктора AffExpr и с помощью add_to_expression!.

Макросы

Рекомендуемый способ создания аффинного выражения — с помощью макроса @expression.

julia> model = Model();

julia> @variable(model, x)
x

julia> @variable(model, y)
y

julia> ex = @expression(model, 2x + y - 1)
2 x + y - 1

Такое выражение можно использовать в целевой функции или добавить в ограничение. Например:

julia> @objective(model, Min, 2 * ex - 1)
4 x + 2 y - 3

julia> objective_function(model)
4 x + 2 y - 3

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

julia> model = Model();

julia> @variable(model, x[i = 1:3]);

julia> @expression(model, expr[i = 1:3], i * sum(x[j] for j in i:3));

julia> expr
3-element Vector{AffExpr}:
 x[1] + x[2] + x[3]
 2 x[2] + 2 x[3]
 3 x[3]

Дополнительные сведения о контейнерах см. в разделе Containers.

Перегрузка операторов

Выражения также можно создавать без макросов. Однако следует отметить, что в некоторых случаях это может быть намного медленнее, чем создание с помощью макросов.

julia> model = Model();

julia> @variable(model, x)
x

julia> @variable(model, y)
y

julia> ex = 2x + y - 1
2 x + y - 1

Конструкторы

Третий способ создания аффинного выражения — с помощью конструктора AffExpr. Первый аргумент — это свободный член, а остальные — это пары переменных и коэффициентов.

julia> model = Model();

julia> @variable(model, x)
x

julia> @variable(model, y)
y

julia> ex = AffExpr(-1.0, x => 2.0, y => 1.0)
2 x + y - 1

add_to_expression!

Четвертый способ создания аффинного выражения — с помощью функции add_to_expression!. По сравнению с методом перегрузки операторов этот подход быстрее, так как позволяет избежать создания временных объектов. Функция add_to_expression! используется внутри макроса @expression.

julia> model = Model();

julia> @variable(model, x)
x

julia> @variable(model, y)
y

julia> ex = AffExpr(-1.0)
-1

julia> add_to_expression!(ex, 2.0, x)
2 x - 1

julia> add_to_expression!(ex, 1.0, y)
2 x + y - 1

Чтобы узнать о некоторых случаях, на которые следует обратить внимание при использовании add_to_expression!](../api.md#JuMP.add_to_expression!), см. раздел [Initializing arrays.

Удаление нулевых членов

Чтобы удалить из аффинного выражения члены с коэффициентом 0, используйте метод drop_zeros!.

julia> model = Model();

julia> @variable(model, x)
x

julia> @expression(model, ex, x + 1 - x)
0 x + 1

julia> drop_zeros!(ex)

julia> ex
1

Коэффициенты

Чтобы получить коэффициент, связанный с переменной в аффинном выражении, используйте метод coefficient.

julia> model = Model();

julia> @variable(model, x)
x

julia> @variable(model, y)
y

julia> @expression(model, ex, 2x + 1)
2 x + 1

julia> coefficient(ex, x)
2.0

julia> coefficient(ex, y)
0.0

Квадратичные выражения

Как и аффинные выражения, квадратичные выражения в JuMP можно создавать четырьмя способами: с помощью макросов, путем перегрузки операторов, с помощью конструкторов и с помощью add_to_expression!.

Макросы

С помощью макроса @expression можно создавать квадратичные выражения путем включения квадратичных членов.

julia> model = Model();

julia> @variable(model, x)
x

julia> @variable(model, y)
y

julia> ex = @expression(model, x^2 + 2 * x * y + y^2 + x + y - 1)
x² + 2 x*y + y² + x + y - 1

Перегрузка операторов

Создавать квадратичные выражения можно также путем перегрузки операторов. При этом действует то же самое предупреждение о производительности (которое приводится в разделе об аффинных выражениях).

julia> model = Model();

julia> @variable(model, x)
x

julia> @variable(model, y)
y

julia> ex = x^2 + 2 * x * y + y^2 + x + y - 1
x² + 2 x*y + y² + x + y - 1

Конструкторы

Квадратичные выражения также можно создавать с помощью конструктора QuadExpr. Первый аргумент — это аффинное выражение, а остальные — это пары, первый член которых — JuMP.UnorderedPair, а второй — коэффициент.

julia> model = Model();

julia> @variable(model, x)
x

julia> @variable(model, y)
y

julia> aff_expr = AffExpr(-1.0, x => 1.0, y => 1.0)
x + y - 1

julia> quad_expr = QuadExpr(
           aff_expr,
           UnorderedPair(x, x) => 1.0,
           UnorderedPair(x, y) => 2.0,
           UnorderedPair(y, y) => 1.0,
       )
x² + 2 x*y + y² + x + y - 1

add_to_expression!

Наконец, добавлять квадратичные члены можно с помощью функции add_to_expression!.

julia> model = Model();

julia> @variable(model, x)
x

julia> @variable(model, y)
y

julia> ex = QuadExpr(x + y - 1.0)
x + y - 1

julia> add_to_expression!(ex, 1.0, x, x)
x² + x + y - 1

julia> add_to_expression!(ex, 2.0, x, y)
x² + 2 x*y + x + y - 1

julia> add_to_expression!(ex, 1.0, y, y)
x² + 2 x*y + y² + x + y - 1

Чтобы узнать о некоторых случаях, на которые следует обратить внимание при использовании add_to_expression!](../api.md#JuMP.add_to_expression!), см. раздел [Initializing arrays.

Удаление нулевых членов

Чтобы удалить из квадратичного выражения члены с коэффициентом 0, используйте метод drop_zeros!.

julia> model = Model();

julia> @variable(model, x)
x

julia> @expression(model, ex, x^2 + x + 1 - x^2)
0 x² + x + 1

julia> drop_zeros!(ex)

julia> ex
x + 1

Коэффициенты

Чтобы получить коэффициент, связанный с парой переменных в квадратичном выражении, используйте метод coefficient.

julia> model = Model();

julia> @variable(model, x)
x

julia> @variable(model, y)
y

julia> @expression(model, ex, 2*x*y + 3*x)
2 x*y + 3 x

julia> coefficient(ex, x, y)
2.0

julia> coefficient(ex, x, x)
0.0

julia> coefficient(ex, y, x)
2.0

julia> coefficient(ex, x)
3.0

Нелинейные выражения

Нелинейные выражения представлены в JuMP объектом NonlinearExpr](../api.md#JuMP.NonlinearExpr). Дополнительные сведения см. в разделе [Nonlinear expressions in detail.

Инициализация массивов

В JuMP реализованы функции zero(AffExpr) и one(AffExpr) для поддержки различных функций в LinearAlgebra (например, доступа к недиагональной части матрицы типа Diagonal).

julia> zero(AffExpr)
0

julia> one(AffExpr)
1

Однако вызов add_to_expression! или API MutableArithmetics для элемента, созданного с помощью zeros или ones, может привести к труднонаходимой ошибке:

julia> x = zeros(AffExpr, 2)
2-element Vector{AffExpr}:
 0
 0

julia> add_to_expression!(x[1], 1.1)
1.1

julia> x
2-element Vector{AffExpr}:
 1.1
 1.1

Обратите внимание, что изменился не только элемент x[1], но и x[2]!

Причина в том, что zeros(AffExpr, 2) однократно вызывает zero(AffExpr), чтобы получить нулевой элемент, а затем создает массив соответствующего размера, заполненный тем же элементом.

Это также происходит при трансляции вызовов, содержащих преобразование 0 или 1:

julia> x = Vector{AffExpr}(undef, 2)
2-element Vector{AffExpr}:
 #undef
 #undef

julia> x .= 0
2-element Vector{AffExpr}:
 0
 0

julia> add_to_expression!(x[1], 1.1)
1.1

julia> x
2-element Vector{AffExpr}:
 1.1
 1.1

Рекомендуемый способ создания массива пустых выражений выглядит так:

julia> x = Vector{AffExpr}(undef, 2)
2-element Vector{AffExpr}:
 #undef
 #undef

julia> for i in eachindex(x)
           x[i] = AffExpr(0.0)
       end

julia> add_to_expression!(x[1], 1.1)
1.1

julia> x
2-element Vector{AffExpr}:
 1.1
 0

Чтобы не обновлять x[1] на месте, можно также прибегнуть к неизменяющей операции:

julia> x = zeros(AffExpr, 2)
2-element Vector{AffExpr}:
 0
 0

julia> x[1] += 1.1
1.1

julia> x
2-element Vector{AffExpr}:
 1.1
 0

Обратите внимание, что для больших выражений этот вариант будет медленнее из-за выделения памяти для дополнительных временных объектов.