Выражения
Аффинные выражения
В 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
Чтобы узнать о некоторых случаях, на которые следует обратить внимание при использовании |
Удаление нулевых членов
Чтобы удалить из аффинного выражения члены с коэффициентом 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
Чтобы узнать о некоторых случаях, на которые следует обратить внимание при использовании |
Удаление нулевых членов
Чтобы удалить из квадратичного выражения члены с коэффициентом 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 реализованы функции 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
Обратите внимание, что для больших выражений этот вариант будет медленнее из-за выделения памяти для дополнительных временных объектов.