Skip to content

Commit

Permalink
Update docstrings
Browse files Browse the repository at this point in the history
  • Loading branch information
blegat committed Sep 24, 2019
1 parent 05f4242 commit c771e5d
Show file tree
Hide file tree
Showing 8 changed files with 127 additions and 39 deletions.
14 changes: 7 additions & 7 deletions docs/src/constraints.md
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,7 @@ following.
One way of adding a group of constraints compactly is the following:
```jldoctest constraint_arrays; setup=:(model=Model(); @variable(model, x))
julia> @constraint(model, con[i = 1:3], i * x <= i + 1)
3-element Array{ConstraintRef{Model,C,Shape} where Shape<:AbstractShape where C,1}:
3-element Array{ConstraintRef{Model,MathOptInterface.ConstraintIndex{MathOptInterface.ScalarAffineFunction{Float64},MathOptInterface.LessThan{Float64}},ScalarShape},1}:
con[1] : x <= 2.0
con[2] : 2 x <= 3.0
con[3] : 3 x <= 4.0
Expand All @@ -264,7 +264,7 @@ julia> con[1]
con[1] : x <= 2.0
julia> con[2:3]
2-element Array{ConstraintRef{Model,C,Shape} where Shape<:AbstractShape where C,1}:
2-element Array{ConstraintRef{Model,MathOptInterface.ConstraintIndex{MathOptInterface.ScalarAffineFunction{Float64},MathOptInterface.LessThan{Float64}},ScalarShape},1}:
con[2] : 2 x <= 3.0
con[3] : 3 x <= 4.0
```
Expand All @@ -273,7 +273,7 @@ Anonymous containers can also be constructed by dropping the name (e.g. `con`)
before the square brackets:
```jldoctest constraint_arrays
julia> @constraint(model, [i = 1:2], i * x <= i + 1)
2-element Array{ConstraintRef{Model,C,Shape} where Shape<:AbstractShape where C,1}:
2-element Array{ConstraintRef{Model,MathOptInterface.ConstraintIndex{MathOptInterface.ScalarAffineFunction{Float64},MathOptInterface.LessThan{Float64}},ScalarShape},1}:
x <= 2.0
2 x <= 3.0
```
Expand All @@ -294,10 +294,10 @@ variables.

```jldoctest constraint_jumparrays; setup=:(model=Model(); @variable(model, x))
julia> @constraint(model, con[i = 1:2, j = 2:3], i * x <= j + 1)
2-dimensional DenseAxisArray{ConstraintRef{Model,C,Shape} where Shape<:AbstractShape where C,2,...} with index sets:
Dimension 1, 1:2
2-dimensional DenseAxisArray{ConstraintRef{Model,MathOptInterface.ConstraintIndex{MathOptInterface.ScalarAffineFunction{Float64},MathOptInterface.LessThan{Float64}},ScalarShape},2,...} with index sets:
Dimension 1, Base.OneTo(2)
Dimension 2, 2:3
And data, a 2×2 Array{ConstraintRef{Model,C,Shape} where Shape<:AbstractShape where C,2}:
And data, a 2×2 Array{ConstraintRef{Model,MathOptInterface.ConstraintIndex{MathOptInterface.ScalarAffineFunction{Float64},MathOptInterface.LessThan{Float64}},ScalarShape},2}:
con[1,2] : x <= 3.0 con[1,3] : x <= 4.0
con[2,2] : 2 x <= 3.0 con[2,3] : 2 x <= 4.0
```
Expand All @@ -311,7 +311,7 @@ similar to the [syntax for constructing](@ref variable_sparseaxisarrays) a

```jldoctest constraint_jumparrays; setup=:(model=Model(); @variable(model, x))
julia> @constraint(model, con[i = 1:2, j = 1:2; i != j], i * x <= j + 1)
JuMP.Containers.SparseAxisArray{ConstraintRef{Model,C,Shape} where Shape<:AbstractShape where C,2,Tuple{Any,Any}} with 2 entries:
JuMP.Containers.SparseAxisArray{ConstraintRef{Model,MathOptInterface.ConstraintIndex{MathOptInterface.ScalarAffineFunction{Float64},MathOptInterface.LessThan{Float64}},ScalarShape},2,Tuple{Int64,Int64}} with 2 entries:
[1, 2] = con[1,2] : x <= 3.0
[2, 1] = con[2,1] : 2 x <= 2.0
```
Expand Down
6 changes: 3 additions & 3 deletions docs/src/variables.md
Original file line number Diff line number Diff line change
Expand Up @@ -324,7 +324,7 @@ return a `DenseAxisArray`. For example:
```jldoctest variables_jump_arrays; setup=:(model=Model())
julia> @variable(model, x[1:2, [:A,:B]])
2-dimensional DenseAxisArray{VariableRef,2,...} with index sets:
Dimension 1, 1:2
Dimension 1, Base.OneTo(2)
Dimension 2, Symbol[:A, :B]
And data, a 2×2 Array{VariableRef,2}:
x[1,A] x[1,B]
Expand Down Expand Up @@ -371,7 +371,7 @@ For example, this applies when indices have a dependence upon previous
indices (called *triangular indexing*). JuMP supports this as follows:
```jldoctest; setup=:(model=Model())
julia> @variable(model, x[i=1:2, j=i:2])
JuMP.Containers.SparseAxisArray{VariableRef,2,Tuple{Any,Any}} with 3 entries:
JuMP.Containers.SparseAxisArray{VariableRef,2,Tuple{Int64,Int64}} with 3 entries:
[1, 2] = x[1,2]
[2, 2] = x[2,2]
[1, 1] = x[1,1]
Expand All @@ -382,7 +382,7 @@ syntax appends a comparison check that depends upon the named indices and is
separated from the indices by a semi-colon (`;`). For example:
```jldoctest; setup=:(model=Model())
julia> @variable(model, x[i=1:4; mod(i, 2)==0])
JuMP.Containers.SparseAxisArray{VariableRef,1,Tuple{Any}} with 2 entries:
JuMP.Containers.SparseAxisArray{VariableRef,1,Tuple{Int64}} with 2 entries:
[4] = x[4]
[2] = x[2]
```
Expand Down
16 changes: 13 additions & 3 deletions src/Containers/container.jl
Original file line number Diff line number Diff line change
@@ -1,11 +1,21 @@
const ArrayIndices{N} = Base.Iterators.ProductIterator{NTuple{N, Base.OneTo{Int}}}
const ArrayIndices{N} = Iterators.ProductIterator{NTuple{N, Base.OneTo{Int}}}
container(f::Function, indices) = container(f, indices, default_container(indices))
default_container(::ArrayIndices) = Array
function container(f::Function, indices::ArrayIndices, ::Type{Array})
return map(I -> f(I...), indices)
end
default_container(::Base.Iterators.ProductIterator) = DenseAxisArray
function container(f::Function, indices::Base.Iterators.ProductIterator,
function _oneto(indices)
if indices isa UnitRange{Int} && indices == 1:length(indices)
return Base.OneTo(length(indices))
end
error("Index set for array is not one-based interval.")
end
function container(f::Function, indices::Iterators.ProductIterator,
::Type{Array})
container(f, Iterators.ProductIterator(_oneto.(indices.iterators)), Array)
end
default_container(::Iterators.ProductIterator) = DenseAxisArray
function container(f::Function, indices::Iterators.ProductIterator,
::Type{DenseAxisArray})
return DenseAxisArray(map(I -> f(I...), indices), indices.iterators...)
end
Expand Down
8 changes: 4 additions & 4 deletions src/Containers/macro.jl
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ _expr_is_splat(::Any) = false
_parse_ref_sets(expr::Expr)
Helper function for macros to construct container objects. Takes an `Expr` that
specifies the container, e.g. `:(x[i=1:3,[:red,:blue]],k=S; i+k <= 6)`, and
specifies the container, e.g. `:(x[i=1:3,[:red,:blue],k=S; i+k <= 6])`, and
returns:
1. `idxvars`: Names for the index variables, e.g. `[:i, gensym(), :k]`
Expand Down Expand Up @@ -118,12 +118,12 @@ _parse_ref_sets(_error::Function, expr) = (Any[], Any[], :())
_build_ref_sets(_error::Function, expr)
Helper function for macros to construct container objects. Takes an `Expr` that
specifies the container, e.g. `:(x[i=1:3,[:red,:blue]],k=S; i+k <= 6)`, and
specifies the container, e.g. `:(x[i=1:3,[:red,:blue],k=S; i+k <= 6])`, and
returns:
1. `idxvars`: Names for the index variables, e.g. `[:i, gensym(), :k]`
2. `idxsets`: Sets used for indexing, e.g. `[1:3, [:red,:blue], S]`
3. `condition`: Expr containing any conditional imposed on indexing, or `:()` if none is present
2. `indices`: Iterators over the indices indexing, e.g.
`Constainers.NestedIterators((1:3, [:red,:blue], S), (i, ##..., k) -> i + k <= 6)`.
"""
function _build_ref_sets(_error::Function, expr)
idxvars, idxsets, condition = _parse_ref_sets(_error, expr)
Expand Down
21 changes: 21 additions & 0 deletions src/Containers/nested_iterator.jl
Original file line number Diff line number Diff line change
@@ -1,3 +1,24 @@
"""
struct NestedIterator{T}
iterators::T # Tuple of functions
condition::Function
end
Iterators over the tuples that are produced by a nested for loop.
For instance, if `length(iterators) == 3` , this corresponds to the tuples
`(i1, i2, i3)` produced by:
```
for i1 in iterators[1]()
for i2 in iterator[2](i1)
for i3 in iterator[3](i1, i2)
if condition(i1, i2, i3)
# produces (i1, i2, i3)
end
end
end
end
```
"""
struct NestedIterator{T}
iterators::T # Tuple of functions
condition::Function
Expand Down
42 changes: 29 additions & 13 deletions src/macros.jl
Original file line number Diff line number Diff line change
Expand Up @@ -864,13 +864,6 @@ function build_variable(_error::Function, info::VariableInfo; extra_kw_args...)
end
return ScalarVariable(info)
end
function build_variable(_error::Function, infos::Vector{<:VariableInfo},
set::AbstractVectorSet; extra_kw_args...)
for (kwarg, _) in extra_kw_args
_error("Unrecognized keyword argument $kwarg")
end
return ConstrainedVariables(infos, moi_set(set, length(infos)))
end

function _macro_error(macroname, args, str...)
error("In `@$macroname($(join(args, ", ")))`: ", str...)
Expand Down Expand Up @@ -1042,12 +1035,28 @@ x = @variable(model, base_name="x", lower_bound=0)
The following are equivalent ways of creating a `DenseAxisArray` of index set
`[:a, :b]` and with respective upper bounds 2 and 3 and names `x[a]` and `x[b]`.
```julia
The upper bound can either be specified in `expr`:
```jldoctest variable_macro; setup = :(using JuMP; model = Model())
ub = Dict(:a => 2, :b => 3)
# Specify everything in `expr`
@variable(model, x[i=keys(ub)] <= ub[i])
# Specify the upper bound using a keyword argument
@variable(model, x[i=keys(ub)], upper_bound=ub[i])
# output
1-dimensional DenseAxisArray{VariableRef,1,...} with index sets:
Dimension 1, Symbol[:a, :b]
And data, a 2-element Array{VariableRef,1}:
x[a]
x[b]
```
or it can be specified with the `upper_bound` keyword argument:
```jldoctest variable_macro
@variable(model, y[i=keys(ub)], upper_bound=ub[i])
# output
1-dimensional DenseAxisArray{VariableRef,1,...} with index sets:
Dimension 1, Symbol[:a, :b]
And data, a 2-element Array{VariableRef,1}:
y[a]
y[b]
```
## Note for extending the variable macro
Expand Down Expand Up @@ -1084,12 +1093,19 @@ JuMP.add_variable(model, JuMP.build_variable(error, info), "x")
The following creates a `DenseAxisArray` of index set `[:a, :b]` and with respective
upper bounds 2 and 3 and names `x[a]` and `x[b]` as with the second example
above but does it without using the `@variable` macro
```jldoctest; setup = :(using JuMP; model = Model())
```jldoctest variable_macro
# Without the `@variable` macro
x = JuMP.Containers.container(i -> begin
info = VariableInfo(false, NaN, true, ub[i], false, NaN, false, NaN, false, false)
x[i] = JuMP.add_variable(model, JuMP.build_variable(error, info), "x[\$i]")
end, Base.Iterators.product(keys(ub))
end, Base.Iterators.product(keys(ub)))
# output
1-dimensional DenseAxisArray{VariableRef,1,...} with index sets:
Dimension 1, Symbol[:a, :b]
And data, a 2-element Array{VariableRef,1}:
x[a]
x[b]
```
The following are equivalent ways of creating a `Matrix` of size
Expand Down
40 changes: 31 additions & 9 deletions src/sd.jl
Original file line number Diff line number Diff line change
Expand Up @@ -144,12 +144,36 @@ function _vectorize_variables(_error::Function, matrix::Matrix)
return vectorize(matrix, SymmetricMatrixShape(n))
end

"""
build_constraint(_error::Function, variables, ::SymMatrixSpace)
Return a `ConstrainedVariables` of shape [`SymmetricMatrixShape`](@ref)
creating variables in `MOI.Reals`, i.e. "free" variables unless they are
constrained after their creation.
This function is used by the [`@variable`](@ref) macro as follows:
```julia
@variable(model, Q[1:2, 1:2], Symmetric)
```
"""
function build_variable(_error::Function, variables, ::SymMatrixSpace)
n = _square_side(_error, variables)
set = MOI.Reals(MOI.dimension(MOI.PositiveSemidefiniteConeTriangle(n)))
shape = SymmetricMatrixShape(n)
return ConstrainedVariables(_vectorize_variables(_error, variables), set, shape)
end

"""
build_constraint(_error::Function, variables, ::PSDCone)
Return a `ConstrainedVariables` of shape [`SymmetricMatrixShape`](@ref)
constraining the variables to be positive semidefinite.
This function is used by the [`@variable`](@ref) macro as follows:
```julia
@variable(model, Q[1:2, 1:2], PSD)
```
"""
function build_variable(_error::Function, variables, ::PSDCone)
n = _square_side(_error, variables)
set = MOI.PositiveSemidefiniteConeTriangle(n)
Expand All @@ -158,16 +182,14 @@ function build_variable(_error::Function, variables, ::PSDCone)
end

"""
function build_constraint(_error::Function, Q::Symmetric{V, M},
::PSDCone) where {V <: AbstractJuMPScalar,
M <: AbstractMatrix{V}}
build_constraint(_error::Function, Q::Symmetric{V, M},
::PSDCone) where {V <: AbstractJuMPScalar,
M <: AbstractMatrix{V}}
Return a `VectorConstraint` of shape [`SymmetricMatrixShape`](@ref) constraining
the matrix `Q` to be positive semidefinite.
This function is used by the [`@variable`](@ref) macro to create a symmetric
semidefinite matrix of variables and by the [`@constraint`](@ref) macros as
follows:
This function is used by the [`@constraint`](@ref) macros as follows:
```julia
@constraint(model, Symmetric(Q) in PSDCone())
```
Expand All @@ -192,9 +214,9 @@ function build_constraint(_error::Function, Q::Symmetric{V, M},
end

"""
function build_constraint(_error::Function,
Q::AbstractMatrix{<:AbstractJuMPScalar},
::PSDCone)
build_constraint(_error::Function,
Q::AbstractMatrix{<:AbstractJuMPScalar},
::PSDCone)
Return a `VectorConstraint` of shape [`SquareMatrixShape`](@ref) constraining
the matrix `Q` to be symmetric and positive semidefinite.
Expand Down
19 changes: 19 additions & 0 deletions src/variables.jl
Original file line number Diff line number Diff line change
Expand Up @@ -799,12 +799,31 @@ function _moi_constrain_variable(backend::MOI.ModelLike, index, info)
end
end

"""
ConstrainedVariables <: AbstractVariable
Vector of variables `scalar_variables` constrained to belong to `set`.
Adding this variable can be thought as doing:
```julia
function JuMP.add_variable(model::Model, variable::JuMP.ConstrainedVariables, names)
var_refs = JuMP.add_variable.(model, variable.scalar_variables,
JuMP.vectorize(names, variable.shape))
JuMP.add_constraint(model, JuMP.VectorConstraint(var_refs, variable.set))
return JuMP.reshape_vector(var_refs, variable.shape)
end
```
but adds the variables with `MOI.add_constrained_variables(model, variable.set)`
instead. See [the MOI documentation](http://www.juliaopt.org/MathOptInterface.jl/v0.9.3/apireference/#Variables-1)
for the difference between adding the variables with `MOI.add_constrained_variables`
and adding them with `MOI.add_variables` and adding the constraint separately.
"""
struct ConstrainedVariables{S <: MOI.AbstractVectorSet, Shape <: AbstractShape,
ScalarVarType <: AbstractVariable} <: AbstractVariable
scalar_variables::Vector{ScalarVarType}
set::S
shape::Shape
end

function ConstrainedVariables(variables::Vector{<:AbstractVariable}, set::MOI.AbstractVectorSet)
return ConstrainedVariables(variables, set, VectorShape())
end
Expand Down

0 comments on commit c771e5d

Please sign in to comment.