From 9dada50020747a7e1c922da10264d61da9dc0716 Mon Sep 17 00:00:00 2001 From: odow Date: Mon, 11 Dec 2023 12:41:42 +1300 Subject: [PATCH] [docs] clean up and clarify macro docstrings --- src/macros/@constraint.jl | 88 +++++++++++++++------------------------ src/macros/@expression.jl | 47 +++++++++++++-------- src/macros/@objective.jl | 34 +++++++++------ 3 files changed, 84 insertions(+), 85 deletions(-) diff --git a/src/macros/@constraint.jl b/src/macros/@constraint.jl index bc898801c7e..27cd02f9052 100644 --- a/src/macros/@constraint.jl +++ b/src/macros/@constraint.jl @@ -4,79 +4,59 @@ # file, You can obtain one at https://mozilla.org/MPL/2.0/. """ - @constraint(model::GenericModel, expr, kwargs...) + @constraint(model, expr, args...; kwargs...) + @constraint(model, [index_sets...], expr, args...; kwargs...) + @constraint(model, name, expr, args...; kwargs...) + @constraint(model, name[index_sets...], expr, args...; kwargs...) Add a constraint described by the expression `expr`. - @constraint(model::GenericModel, ref[i=..., j=..., ...], expr, kwargs...) +The `name` argument is optional. If index sets are passed, a container is built +and the connstraint may depend on the indices of the index ssets. -Add a group of constraints described by the expression `expr` parametrized by -`i`, `j`, ... +The expression `expr` may be one of following forms: -The expression `expr` can either be + * `func in set`, constraining the function `func` to belong to the set `set`, + which is either a [`MOI.AbstractSet`](@ref) or one of the JuMP shortcuts like + [`SecondOrderCone`](@ref) or [`PSDCone`](@ref) -* of the form `func in set` constraining the function `func` to belong to the - set `set` which is either a [`MOI.AbstractSet`](@ref) - or one of the JuMP shortcuts [`SecondOrderCone`](@ref), - [`RotatedSecondOrderCone`](@ref) and [`PSDCone`](@ref), e.g. - `@constraint(model, [1, x-1, y-2] in SecondOrderCone())` constrains the norm - of `[x-1, y-2]` be less than 1; + * `a b`, where `` is one of `==`, `≥`, `>=`, `≤`, `<=` -* of the form `a sign b`, where `sign` is one of `==`, `≥`, `>=`, `≤` and - `<=` building the single constraint enforcing the comparison to hold for the - expression `a` and `b`, e.g. `@constraint(model, x^2 + y^2 == 1)` constrains - `x` and `y` to lie on the unit circle; + * `l <= f <= u` or `u >= f >= l`, constraining the expression `f` to lie + between `l` and `u` -* of the form `a ≤ b ≤ c` or `a ≥ b ≥ c` (where `≤` and `<=` (resp. `≥` and - `>=`) can be used interchangeably) constraining the paired the expression - `b` to lie between `a` and `c`; + * `f(x) ⟂ x`, which defines a complementarity constraint -* of the forms `@constraint(m, a .sign b)` or - `@constraint(m, a .sign b .sign c)` which broadcast the constraint creation to - each element of the vectors. + * `z --> {expr}`, which defines an indicator constraint that activates + when `z` is `1` -The recognized keyword arguments in `kwargs` are the following: + * `!z --> {expr}`, which defines an indicator constraint that activates + when `z` is `0` -* `base_name`: Sets the name prefix used to generate constraint names. It - corresponds to the constraint name for scalar constraints, otherwise, the - constraint names are set to `base_name[...]` for each index `...` of the axes - `axes`. + * `z <--> {expr}`, which defines a reified constraint -* `container`: Specify the container type. + * `expr := rhs`, which defines a Boolean equality constraint -* `set_string_name::Bool = true`: control whether to set the - [`MOI.ConstraintName`](@ref) attribute. Passing `set_string_name = false` can - improve performance. +Broadcasted comparison operators like `.==` are also supported for the case when +the left- and right-hand sides of the comparison operator are arrays. -## Note for extending the constraint macro +JuMP extensions may additionally provide support for constraint expressions +which are not listed here. -Each constraint will be created using -`add_constraint(m, build_constraint(error_fn, func, set))` where +## Keyword arguments -* `error_fn` is an error function showing the constraint call in addition to the - error message given as argument, + * `base_name`: sets the name prefix used to generate constraint names. It + corresponds to the constraint name for scalar constraints, otherwise, the + constraint names are set to `base_name[...]` for each index `...`. -* `func` is the expression that is constrained -* and `set` is the set in which it is constrained to belong. + * `container = :Auto`: force the container type by passing `container = Array`, + `container = DenseAxisArray`, `container = SparseAxisArray`, or any another + container type which is supported by a JuMP extension. -For `expr` of the first type (i.e. `@constraint(m, func in set)`), `func` and -`set` are passed unchanged to `build_constraint` but for the other types, they -are determined from the expressions and signs. For instance, -`@constraint(m, x^2 + y^2 == 1)` is transformed into -`add_constraint(m, build_constraint(error_fn, x^2 + y^2, MOI.EqualTo(1.0)))`. + * `set_string_name::Bool = true`: control whether to set the [`MOI.ConstraintName`](@ref) + attribute. Passing `set_string_name = false` can improve performance. -To extend JuMP to accept new constraints of this form, it is necessary to add -the corresponding methods to `build_constraint`. Note that this will likely mean -that either `func` or `set` will be some custom type, rather than e.g. a -`Symbol`, since we will likely want to dispatch on the type of the function or -set appearing in the constraint. - -For extensions that need to create constraints with more information than just -`func` and `set`, an additional positional argument can be specified to -`@constraint` that will then be passed on `build_constraint`. Hence, we can -enable this syntax by defining extensions of -`build_constraint(error_fn, func, set, my_arg; kwargs...)`. This produces the -user syntax: `@constraint(model, ref[...], expr, my_arg, kwargs...)`. +Other keyword arguments may be supported by JuMP extensions. """ macro constraint(input_args...) error_fn(str...) = _macro_error(:constraint, input_args, __source__, str...) diff --git a/src/macros/@expression.jl b/src/macros/@expression.jl index 1fa12d06f4a..3e1bd484075 100644 --- a/src/macros/@expression.jl +++ b/src/macros/@expression.jl @@ -4,37 +4,44 @@ # file, You can obtain one at https://mozilla.org/MPL/2.0/. """ - @expression(args...) + @expression(model::GenericModel, expression) + @expression(model::GenericModel, [index_sets...], expression) + @expression(model::GenericModel, name, expression) + @expression(model::GenericModel, name[index_sets...], expression) -Efficiently builds a linear or quadratic expression but does not add to model -immediately. Instead, returns the expression which can then be inserted in other -constraints. +Efficiently builds and returns an expression. + +The `name` argument is optional. If index sets are passed, a container is built +and the expression may depend on the indices of the index ssets. + +## Keyword arguments + + * `container = :Auto`: force the container type by passing `container = Array`, + `container = DenseAxisArray`, `container = SparseAxisArray`, or any another + container type which is supported by a JuMP extension. ## Example -```jldoctest expression_docstring +```jldoctest julia> model = Model(); julia> @variable(model, x[1:5]); -julia> @variable(model, y); - -julia> @variable(model, z); - julia> @expression(model, shared, sum(i * x[i] for i in 1:5)) x[1] + 2 x[2] + 3 x[3] + 4 x[4] + 5 x[5] -julia> @constraint(model, shared + y >= 5) -x[1] + 2 x[2] + 3 x[3] + 4 x[4] + 5 x[5] + y ≥ 5 - -julia> @constraint(model, shared + z <= 10) -x[1] + 2 x[2] + 3 x[3] + 4 x[4] + 5 x[5] + z ≤ 10 +julia> shared +x[1] + 2 x[2] + 3 x[3] + 4 x[4] + 5 x[5] ``` -The `ref` accepts index sets in the same way as `@variable`, and those indices -can be used in the construction of the expressions: +In the same way as [`@variable`](@ref), the second argument may define index +sets, and those indices can be used in the construction of the expressions: + +```jldoctest +julia> model = Model(); + +julia> @variable(model, x[1:3]); -```jldoctest expression_docstring julia> @expression(model, expr[i = 1:3], i * sum(x[j] for j in 1:3)) 3-element Vector{AffExpr}: x[1] + x[2] + x[3] @@ -44,7 +51,11 @@ julia> @expression(model, expr[i = 1:3], i * sum(x[j] for j in 1:3)) Anonymous syntax is also supported: -```jldoctest expression_docstring +```jldoctest +julia> model = Model(); + +julia> @variable(model, x[1:3]); + julia> expr = @expression(model, [i in 1:3], i * sum(x[j] for j in 1:3)) 3-element Vector{AffExpr}: x[1] + x[2] + x[3] diff --git a/src/macros/@objective.jl b/src/macros/@objective.jl index e0e2eab67bd..074c532bffc 100644 --- a/src/macros/@objective.jl +++ b/src/macros/@objective.jl @@ -6,18 +6,17 @@ """ @objective(model::GenericModel, sense, func) -Set the objective sense to `sense` and objective function to `func`. The -objective sense can be either `Min`, `Max`, `MOI.MIN_SENSE`, `MOI.MAX_SENSE` or -`MOI.FEASIBILITY_SENSE`; see [`MOI.ObjectiveSense`](@ref). +Set the objective sense to `sense` and objective function to `func`. -In order to set the sense programmatically, i.e., when `sense` is a Julia -variable whose value is the sense, one of the three `MOI.ObjectiveSense` values -should be used. +The objective sense can be either `Min`, `Max`, `MOI.MIN_SENSE`, `MOI.MAX_SENSE` +or `MOI.FEASIBILITY_SENSE`. In order to set the sense programmatically, that is, +when `sense` is a variable whose value is the sense, one of the three +[`MOI.OptimizationSense`](@ref) values must be used. ## Example -To minimize the value of the variable `x`, do as follows: -```jldoctest @objective +Minimize the value of the variable `x`, do: +```jldoctest julia> model = Model(); julia> @variable(model, x) @@ -27,15 +26,24 @@ julia> @objective(model, Min, x) x ``` -To maximize the value of the affine expression `2x - 1`, do as follows: -```jldoctest @objective +Maximize the value of the affine expression `2x - 1`: +```jldoctest +julia> model = Model(); + +julia> @variable(model, x) +x + julia> @objective(model, Max, 2x - 1) 2 x - 1 ``` -To set a quadratic objective and set the objective sense programmatically, do -as follows: -```jldoctest @objective +Set the objective sense programmatically: +```jldoctest +julia> model = Model(); + +julia> @variable(model, x) +x + julia> sense = MIN_SENSE MIN_SENSE::OptimizationSense = 0