-
Notifications
You must be signed in to change notification settings - Fork 94
Tutorial about expressions #1553
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
28 commits
Select commit
Hold shift + click to select a range
c4afbda
Create manipulating_expressions.md
dourouc05 87259d4
Update manipulating_expressions.md
dourouc05 308852e
Update manipulating_expressions.md
dourouc05 0bcec0e
Update make.jl
dourouc05 0c53f5f
Update manipulating_expressions.md
dourouc05 536fd98
Update manipulating_expressions.md
dourouc05 2a3c4b3
Update manipulating_expressions.md
dourouc05 477f22a
Update manipulating_expressions.md
dourouc05 f8c1d1d
Update manipulating_expressions.md
dourouc05 4cfb8a1
Update manipulating_expressions.md
dourouc05 67be665
Update manipulating_expressions.md
dourouc05 ec3ef24
Update manipulating_expressions.md
dourouc05 5332c05
Update manipulating_expressions.md
dourouc05 eb86709
Update manipulating_expressions.md
dourouc05 2394697
Update manipulating_expressions.md
dourouc05 85f4f5a
Add docs for scalarize.
dourouc05 d6987b8
Add documentation for eachscalar.
dourouc05 9bcb684
Update reference.md
dourouc05 2317e35
Update manipulating_expressions.md
dourouc05 fa5cbe7
Update manipulating_expressions.md
dourouc05 0c53e5e
Update manipulating_expressions.md
dourouc05 89bdf20
Update manipulating_expressions.md
dourouc05 9088d17
Update manipulating_expressions.md
dourouc05 743df9b
Update manipulating_expressions.md
dourouc05 8b98048
Update manipulating_expressions.md
dourouc05 470ff4a
Update manipulating_expressions.md
dourouc05 76e5e7d
Update manipulating_expressions.md
dourouc05 af5e20c
Update manipulating_expressions.md
odow File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,142 @@ | ||
```@meta | ||
CurrentModule = MathOptInterface | ||
DocTestSetup = quote | ||
using MathOptInterface | ||
const MOI = MathOptInterface | ||
end | ||
DocTestFilters = [r"MathOptInterface|MOI"] | ||
``` | ||
|
||
# Manipulating expressions | ||
|
||
This guide highlights a syntactically appealing way to build expressions at the | ||
MOI level, but also to look at their contents. It may be especially useful | ||
when writing models or bridge code. | ||
|
||
## Creating functions | ||
|
||
This section details the ways to create functions with MathOptInterface. | ||
|
||
### Creating scalar affine functions | ||
|
||
The simplest scalar function is simply a variable: | ||
|
||
```jldoctest expr; setup=:(model = MOI.Utilities.CachingOptimizer(MOI.Utilities.Model{Float64}(), MOI.Utilities.AUTOMATIC); ) | ||
julia> x = MOI.add_variable(model) # Create the variable x | ||
MathOptInterface.VariableIndex(1) | ||
julia> f1 = MOI.SingleVariable(x) # A function with the single variable x | ||
MathOptInterface.SingleVariable(MathOptInterface.VariableIndex(1)) | ||
``` | ||
|
||
This type of function is extremely simple; to express more complex functions, | ||
other types must be used. For instance, a [`ScalarAffineFunction`](@ref) is a | ||
sum of linear terms (a factor times a variable) and a constant. Such an object | ||
can be built using the standard constructor: | ||
|
||
```jldoctest expr | ||
julia> f2 = MOI.ScalarAffineFunction([MOI.ScalarAffineTerm(1, x)], 2) # x + 2 | ||
MathOptInterface.ScalarAffineFunction{Int64}(MathOptInterface.ScalarAffineTerm{Int64}[ScalarAffineTerm{Int64}(1, VariableIndex(1))], 2) | ||
``` | ||
|
||
However, you can also use operators to build the same scalar function: | ||
|
||
```jldoctest expr | ||
julia> f2 = MOI.SingleVariable(x) + 2 # x + 2 | ||
MathOptInterface.ScalarAffineFunction{Int64}(MathOptInterface.ScalarAffineTerm{Int64}[ScalarAffineTerm{Int64}(1, VariableIndex(1))], 2) | ||
``` | ||
|
||
### Creating scalar quadratic functions | ||
|
||
Scalar quadratic functions are stored in [`ScalarQuadraticFunction`](@ref) | ||
objects, in a way that is highly similar to scalar affine functions. You can | ||
obtain a quadratic function as a product of affine functions: | ||
|
||
```jldoctest expr | ||
julia> f3 = 1 * MOI.SingleVariable(x) * MOI.SingleVariable(x) # x² | ||
MathOptInterface.ScalarQuadraticFunction{Int64}(MathOptInterface.ScalarQuadraticTerm{Int64}[ScalarQuadraticTerm{Int64}(2, VariableIndex(1), VariableIndex(1))], MathOptInterface.ScalarAffineTerm{Int64}[], 0) | ||
julia> f4 = f2 * f2 # (x + 2)² | ||
MathOptInterface.ScalarQuadraticFunction{Int64}(MathOptInterface.ScalarQuadraticTerm{Int64}[ScalarQuadraticTerm{Int64}(2, VariableIndex(1), VariableIndex(1))], MathOptInterface.ScalarAffineTerm{Int64}[ScalarAffineTerm{Int64}(2, VariableIndex(1)), ScalarAffineTerm{Int64}(2, VariableIndex(1))], 4) | ||
julia> f4 = f2^2 # (x + 2)² too | ||
MathOptInterface.ScalarQuadraticFunction{Int64}(MathOptInterface.ScalarQuadraticTerm{Int64}[ScalarQuadraticTerm{Int64}(2, VariableIndex(1), VariableIndex(1))], MathOptInterface.ScalarAffineTerm{Int64}[ScalarAffineTerm{Int64}(2, VariableIndex(1)), ScalarAffineTerm{Int64}(2, VariableIndex(1))], 4) | ||
``` | ||
|
||
### Creating vector functions | ||
|
||
A vector function is a function with several values, irrespective of the number | ||
of input variables. Similarly to scalar functions, there are three main types | ||
odow marked this conversation as resolved.
Show resolved
Hide resolved
|
||
of vector functions: [`VectorOfVariables`](@ref), | ||
[`VectorAffineFunction`](@ref), and [`VectorQuadraticFunction`](@ref). | ||
|
||
The easiest way to create a vector function is to stack several scalar | ||
functions using [`Utilities.vectorize`](@ref). It takes a vector as input, | ||
and the generated vector function (of the most appropriate type) has each | ||
dimension corresponding to a dimension of the vector. | ||
|
||
```jldoctest expr | ||
julia> f5 = MOI.Utilities.vectorize([f2, 2 * f2]) | ||
MathOptInterface.VectorAffineFunction{Int64}(MathOptInterface.VectorAffineTerm{Int64}[VectorAffineTerm{Int64}(1, ScalarAffineTerm{Int64}(1, VariableIndex(1))), VectorAffineTerm{Int64}(2, ScalarAffineTerm{Int64}(2, VariableIndex(1)))], [2, 4]) | ||
``` | ||
|
||
!!! warning | ||
[`Utilities.vectorize`](@ref) only takes a vector of similar scalar | ||
functions: you cannot mix [`SingleVariable`](@ref) and | ||
[`ScalarAffineFunction`](@ref), for instance. In practice, it means that | ||
`Utilities.vectorize([f1, f2])` does not work; you should rather use | ||
`Utilities.vectorize([1 * f1, f2])` instead to only have | ||
[`ScalarAffineFunction`](@ref) objects. | ||
|
||
## Canonicalizing functions | ||
|
||
In more advanced use cases, you might need to ensure that a function is | ||
"canonical". Functions are stored as an array of terms, but there is no check | ||
that these terms are redundant: a [`ScalarAffineFunction`](@ref) object might | ||
have two terms with the same variable, like `x + x + 1`. These terms could be | ||
merged without changing the semantics of the function: `2x + 1`. | ||
|
||
Working with these objects might be cumbersome. Canonicalization helps maintain | ||
redundancy to zero. | ||
|
||
[`Utilities.is_canonical`](@ref) checks whether a function is already in its | ||
canonical form: | ||
|
||
```jldoctest expr | ||
julia> MOI.Utilities.is_canonical(f2 + f2) # (x + 2) + (x + 2) is stored as x + x + 4 | ||
false | ||
``` | ||
|
||
[`Utilities.canonical`](@ref) returns the equivalent canonical version of the | ||
function: | ||
|
||
```jldoctest expr | ||
julia> MOI.Utilities.canonical(f2 + f2) # Returns 2x + 4 | ||
MathOptInterface.ScalarAffineFunction{Int64}(MathOptInterface.ScalarAffineTerm{Int64}[ScalarAffineTerm{Int64}(2, VariableIndex(1))], 4) | ||
``` | ||
|
||
## Exploring functions | ||
|
||
At some point, you might need to dig into a function, for instance to map it | ||
into solver constructs. | ||
|
||
### Vector functions | ||
|
||
[`Utilities.scalarize`](@ref) returns a vector of scalar functions from a | ||
vector function: | ||
|
||
```jldoctest expr | ||
julia> MOI.Utilities.scalarize(f5) # Returns a vector [f2, 2 * f2]. | ||
2-element Array{MathOptInterface.ScalarAffineFunction{Int64},1}: | ||
MathOptInterface.ScalarAffineFunction{Int64}(MathOptInterface.ScalarAffineTerm{Int64}[ScalarAffineTerm{Int64}(1, VariableIndex(1))], 2) | ||
MathOptInterface.ScalarAffineFunction{Int64}(MathOptInterface.ScalarAffineTerm{Int64}[ScalarAffineTerm{Int64}(2, VariableIndex(1))], 4) | ||
``` | ||
|
||
!!! note | ||
[`Utilities.eachscalar`](@ref) returns an iterator on the dimensions, which | ||
serves the same purpose as [`Utilities.scalarize`](@ref). | ||
|
||
[`output_dimension`](@ref) returns the number of dimensions of the | ||
output of a function: | ||
|
||
```jldoctest expr | ||
julia> MOI.output_dimension(f5) | ||
2 | ||
``` |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -492,7 +492,20 @@ function ScalarFunctionIterator(f::MOI.VectorQuadraticFunction) | |
) | ||
end | ||
|
||
""" | ||
eachscalar(f::MOI.AbstractVectorFunction) | ||
|
||
Returns an iterator for the scalar components of the vector function. | ||
|
||
See also [`scalarize`](@ref). | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm surprised this worked. I thought it had to be |
||
""" | ||
eachscalar(f::MOI.AbstractVectorFunction) = ScalarFunctionIterator(f) | ||
|
||
""" | ||
eachscalar(f::MOI.AbstractVector) | ||
|
||
Returns an iterator for the scalar components of the vector. | ||
""" | ||
eachscalar(f::AbstractVector) = f | ||
|
||
function Base.iterate(it::ScalarFunctionIterator, state = 1) | ||
|
@@ -3067,12 +3080,26 @@ function operate( | |
return MOI.VectorQuadraticFunction(quadratic_terms, affine_terms, constant) | ||
end | ||
|
||
# Similar to `eachscalar` but faster, see | ||
# https://github.com/jump-dev/MathOptInterface.jl/issues/418 | ||
""" | ||
scalarize(func::MOI.VectorOfVariables, ignore_constants::Bool = false) | ||
|
||
Returns a vector of scalar functions making up the vector function in the form | ||
of a `Vector{MOI.SingleVariable}`. | ||
|
||
See also [`eachscalar`](@ref). | ||
""" | ||
function scalarize(f::MOI.VectorOfVariables, ignore_constants::Bool = false) | ||
return MOI.SingleVariable.(f.variables) | ||
end | ||
|
||
""" | ||
scalarize(func::MOI.VectorAffineFunction{T}, ignore_constants::Bool = false) | ||
|
||
Returns a vector of scalar functions making up the vector function in the form | ||
of a `Vector{MOI.ScalarAffineFunction{T}}`. | ||
|
||
See also [`eachscalar`](@ref). | ||
""" | ||
function scalarize( | ||
f::MOI.VectorAffineFunction{T}, | ||
ignore_constants::Bool = false, | ||
|
@@ -3092,6 +3119,14 @@ function scalarize( | |
return functions | ||
end | ||
|
||
""" | ||
scalarize(func::MOI.VectorQuadraticFunction{T}, ignore_constants::Bool = false) | ||
|
||
Returns a vector of scalar functions making up the vector function in the form | ||
of a `Vector{MOI.ScalarQuadraticFunction{T}}`. | ||
|
||
See also [`eachscalar`](@ref). | ||
""" | ||
function scalarize( | ||
f::MOI.VectorQuadraticFunction{T}, | ||
ignore_constants::Bool = false, | ||
|
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.