Skip to content

Commit

Permalink
[docs] improve docstrings by adding examples (#3761)
Browse files Browse the repository at this point in the history
  • Loading branch information
odow authored May 29, 2024
1 parent 51ac43c commit 99ab0b2
Show file tree
Hide file tree
Showing 12 changed files with 452 additions and 104 deletions.
60 changes: 57 additions & 3 deletions src/JuMP.jl
Original file line number Diff line number Diff line change
Expand Up @@ -598,13 +598,30 @@ end
set_string_names_on_creation(model::GenericModel, value::Bool)
Set the default argument of the `set_string_name` keyword in the
[`@variable`](@ref) and [`@constraint`](@ref) macros to `value`. This is used to
determine whether to assign `String` names to all variables and constraints in
`model`.
[`@variable`](@ref) and [`@constraint`](@ref) macros to `value`.
The `set_string_name` keyword is used to determine whether to assign `String`
names to all variables and constraints in `model`.
By default, `value` is `true`. However, for larger models calling
`set_string_names_on_creation(model, false)` can improve performance at the cost
of reducing the readability of printing and solver log messages.
## Example
```jldoctest
julia> import HiGHS
julia> model = Model(HiGHS.Optimizer);
julia> set_string_names_on_creation(model)
true
julia> set_string_names_on_creation(model, false)
julia> set_string_names_on_creation(model)
false
```
"""
function set_string_names_on_creation(model::GenericModel, value::Bool)
model.set_string_names_on_creation = value
Expand Down Expand Up @@ -1206,6 +1223,43 @@ Base.iterate(::AbstractJuMPScalar, state) = nothing
Base.isempty(::AbstractJuMPScalar) = false
Base.length(::AbstractJuMPScalar) = 1

"""
isequal_canonical(
x::T,
y::T
) where {T<:AbstractJuMPScalar,AbstractArray{<:AbstractJuMPScalar}}
Return `true` if `x` is equal to `y` after dropping zeros and disregarding
the order.
This method is mainly useful for testing, because fallbacks like `x == y` do not
account for valid mathematical comparisons like `x[1] + 0 x[2] + 1 == x[1] + 1`.
## Example
```jldoctest
julia> model = Model();
julia> @variable(model, x[1:2]);
julia> a = x[1] + 1.0
x[1] + 1
julia> b = x[1] + x[2] + 1.0
x[1] + x[2] + 1
julia> add_to_expression!(b, -1.0, x[2])
x[1] + 0 x[2] + 1
julia> a == b
false
julia> isequal_canonical(a, b)
true
```
"""
function isequal_canonical end

# Check if two arrays of AbstractJuMPScalars are equal. Useful for testing.
function isequal_canonical(
x::AbstractArray{<:AbstractJuMPScalar},
Expand Down
9 changes: 0 additions & 9 deletions src/aff_expr.jl
Original file line number Diff line number Diff line change
Expand Up @@ -629,15 +629,6 @@ function SparseArrays.dropzeros(aff::GenericAffExpr)
return result
end

"""
isequal_canonical(
aff::GenericAffExpr{C,V},
other::GenericAffExpr{C,V}
) where {C,V}
Return `true` if `aff` is equal to `other` after dropping zeros and disregarding
the order. Mainly useful for testing.
"""
function isequal_canonical(
aff::GenericAffExpr{C,V},
other::GenericAffExpr{C,V},
Expand Down
68 changes: 58 additions & 10 deletions src/callbacks.jl
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,33 @@
Return an [`MOI.CallbackNodeStatusCode`](@ref) enum, indicating if the current
primal solution available from [`callback_value`](@ref) is integer feasible.
## Example
```jldoctest; filter=r"CALLBACK_NODE_STATUS_.+"
julia> import GLPK
julia> model = Model(GLPK.Optimizer);
julia> @variable(model, x <= 10, Int);
julia> @objective(model, Max, x);
julia> function my_callback_function(cb_data)
status = callback_node_status(cb_data, model)
println("Status is: ", status)
return
end
my_callback_function (generic function with 1 method)
julia> set_attribute(model, GLPK.CallbackFunction(), my_callback_function)
julia> optimize!(model)
Status is: CALLBACK_NODE_STATUS_UNKNOWN
Status is: CALLBACK_NODE_STATUS_UNKNOWN
Status is: CALLBACK_NODE_STATUS_INTEGER
Status is: CALLBACK_NODE_STATUS_INTEGER
```
"""
function callback_node_status(cb_data, model::GenericModel)
# TODO(odow):
Expand All @@ -29,11 +56,41 @@ end

"""
callback_value(cb_data, x::GenericVariableRef)
callback_value(cb_data, x::Union{GenericAffExpr,GenericQuadExpr})
Return the primal solution of a variable inside a callback.
Return the primal solution of `x` inside a callback.
`cb_data` is the argument to the callback function, and the type is dependent on
the solver.
Use [`callback_node_status`](@ref) to check whether a solution is available.
## Example
```jldoctest
julia> import GLPK
julia> model = Model(GLPK.Optimizer);
julia> @variable(model, x <= 10, Int);
julia> @objective(model, Max, x);
julia> function my_callback_function(cb_data)
status = callback_node_status(cb_data, model)
if status == MOI.CALLBACK_NODE_STATUS_INTEGER
println("Solution is: ", callback_value(cb_data, x))
end
return
end
my_callback_function (generic function with 1 method)
julia> set_attribute(model, GLPK.CallbackFunction(), my_callback_function)
julia> optimize!(model)
Solution is: 10.0
Solution is: 10.0
```
"""
function callback_value(cb_data, x::GenericVariableRef)
# TODO(odow):
Expand All @@ -52,15 +109,6 @@ function callback_value(cb_data, x::GenericVariableRef)
)
end

"""
callback_value(cb_data, expr::Union{GenericAffExpr, GenericQuadExpr})
Return the primal solution of an affine or quadratic expression inside a
callback by getting the value for each variable appearing in the expression.
`cb_data` is the argument to the callback function, and the type is dependent on
the solver.
"""
function callback_value(cb_data, expr::Union{GenericAffExpr,GenericQuadExpr})
return value(expr) do x
return callback_value(cb_data, x)
Expand Down
40 changes: 38 additions & 2 deletions src/constraints.jl
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,19 @@ end
index(cr::ConstraintRef)::MOI.ConstraintIndex
Return the index of the constraint that corresponds to `cr` in the MOI backend.
## Example
```jldoctest
julia> model = Model();
julia> @variable(model, x);
julia> @constraint(model, c, x >= 0);
julia> index(c)
MathOptInterface.ConstraintIndex{MathOptInterface.ScalarAffineFunction{Float64}, MathOptInterface.GreaterThan{Float64}}(1)
```
"""
index(cr::ConstraintRef) = cr.index

Expand Down Expand Up @@ -60,6 +73,7 @@ julia> MOI.get(model_new, MOI.ConstraintName(), c)
ERROR: ConstraintNotOwned{ConstraintRef{Model, MathOptInterface.ConstraintIndex{MathOptInterface.ScalarAffineFunction{Float64}, MathOptInterface.GreaterThan{Float64}}, ScalarShape}}(c : x ≥ 0)
Stacktrace:
[...]
```
"""
struct ConstraintNotOwned{C<:ConstraintRef} <: Exception
constraint_ref::C
Expand Down Expand Up @@ -487,6 +501,9 @@ end
constraint_ref_with_index(model::AbstractModel, index::MOI.ConstraintIndex)
Return a `ConstraintRef` of `model` corresponding to `index`.
This function is a helper function used internally by JuMP and some JuMP
extensions. It should not need to be called in user-code.
"""
function constraint_ref_with_index(
model::AbstractModel,
Expand All @@ -497,6 +514,7 @@ function constraint_ref_with_index(
)
return ConstraintRef(model, index, ScalarShape())
end

function constraint_ref_with_index(
model::AbstractModel,
index::MOI.ConstraintIndex{
Expand Down Expand Up @@ -607,7 +625,25 @@ end
"""
is_valid(model::GenericModel, con_ref::ConstraintRef{<:AbstractModel})
Return `true` if `constraint_ref` refers to a valid constraint in `model`.
Return `true` if `con_ref` refers to a valid constraint in `model`.
## Example
```jldoctest
julia> model = Model();
julia> @variable(model, x);
julia> @constraint(model, c, 2 * x <= 1);
julia> is_valid(model, c)
true
julia> model_2 = Model();
julia> is_valid(model_2, c)
false
```
"""
function is_valid(model::GenericModel, con_ref::ConstraintRef{<:AbstractModel})
return (
Expand Down Expand Up @@ -1357,7 +1393,7 @@ true
julia> dual(c)
-2.0
````
```
"""
function dual(
con_ref::ConstraintRef{<:AbstractModel,<:MOI.ConstraintIndex};
Expand Down
9 changes: 9 additions & 0 deletions src/macros/@variable.jl
Original file line number Diff line number Diff line change
Expand Up @@ -401,6 +401,15 @@ end
Given an (in)equality symbol `T`, return a new `Val` object with the opposite
(in)equality symbol.
This function is intended for use in JuMP extensions.
## Example
```jldoctest
julia> reverse_sense(Val(:>=))
Val{:<=}()
```
"""
function reverse_sense end
reverse_sense(::Val{:<=}) = Val(:>=)
Expand Down
10 changes: 0 additions & 10 deletions src/nlp.jl
Original file line number Diff line number Diff line change
Expand Up @@ -263,11 +263,6 @@ function add_nonlinear_parameter(model::Model, value::Real)
return NonlinearParameter(model, p.value)
end

"""
index(p::NonlinearParameter)::MOI.Nonlinear.ParameterIndex
Return the index of the nonlinear parameter associated with `p`.
"""
index(p::NonlinearParameter) = MOI.Nonlinear.ParameterIndex(p.index)

"""
Expand Down Expand Up @@ -372,11 +367,6 @@ function MOI.Nonlinear.parse_expression(
return MOI.Nonlinear.parse_expression(model, expr, index, parent)
end

"""
index(ex::NonlinearExpression)::MOI.Nonlinear.ExpressionIndex
Return the index of the nonlinear expression associated with `ex`.
"""
index(ex::NonlinearExpression) = MOI.Nonlinear.ExpressionIndex(ex.index)

"""
Expand Down
13 changes: 13 additions & 0 deletions src/nlp_expr.jl
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,19 @@ _parens(::MIME"text/latex") = "\\left(", "\\right)", "{", "}", "\\textsf"
Return the string that should be printed for the operator `op` when
[`function_string`](@ref) is called with `mime` and `x`.
## Example
```jldoctest
julia> model = Model();
julia> @variable(model, x[1:2], Bin);
julia> f = @expression(model, x[1] || x[2]);
julia> op_string(MIME("text/plain"), f, Val(:||))
"||"
```
"""
op_string(::MIME, ::GenericNonlinearExpr, ::Val{op}) where {op} = string(op)
op_string(::MIME"text/latex", ::GenericNonlinearExpr, ::Val{:&&}) = "\\wedge"
Expand Down
Loading

0 comments on commit 99ab0b2

Please sign in to comment.