From 5911d9c9d2dcd5ad76586282cecfd210d049cf39 Mon Sep 17 00:00:00 2001 From: odow Date: Thu, 23 Aug 2018 16:33:30 +1200 Subject: [PATCH 01/11] Discuss deleting variables and variable bounds --- docs/src/variables.md | 47 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 43 insertions(+), 4 deletions(-) diff --git a/docs/src/variables.md b/docs/src/variables.md index 3456f515de1..5d2006a38d6 100644 --- a/docs/src/variables.md +++ b/docs/src/variables.md @@ -44,6 +44,10 @@ This code does three things: To reduce confusion, we will attempt, where possible, to always refer to variables with their corresponding prefix. +!!! warn + If you create two JuMP variables with the same name, an error will be + thrown. + JuMP variables can have attributes, such as names or an initial primal start value. We illustrate the name attribute in the following example: ```jldoctest variables @@ -165,9 +169,44 @@ julia> JuMP.lower_bound(x) 1.0 ``` -!!! warn - If you create two JuMP variables with the same name, an error will be - thrown. +Another option is to use the `JuMP.setlowerbound` and `JuMP.setupperbound` +functions. These can also be used to modify an existing variable bound. For +example: +```jldoctest; setup=:(model=Model()) +julia> @variable(model, x >= 1) +x + +julia> JuMP.lowerbound(x) +1.0 + +julia> JuMP.setlowerbound(x, 2) + +julia> JuMP.lowerbound(x) +2.0 +``` + +Finally, we can delete variable bounds using `JuMP.deletelowerbound` and +`JuMP.deleteupperbound`: +```jldoctest; setup=:(model=Model()) +julia> @variable(model, 1 <= x <= 2) +x + +julia> JuMP.lowerbound(x) +1.0 + +julia> JuMP.deletelowerbound(x) + +julia> JuMP.haslowerbound(x) +false + +julia> JuMP.upperbound(x) +2.0 + +julia> JuMP.deleteupperbound(x) + +julia> JuMP.hasupperbound(x) +false +``` ## Variable containers @@ -470,7 +509,7 @@ Dict{Symbol,Symmetric{JuMP.VariableRef,Array{JuMP.VariableRef,2}}} with 2 entrie ## Deleting variables -JuMP supports the deletion of optimization variables. To delete variables, we +JuMP supports the deletion of optimization variables. To delete variables, we can use the `JuMP.delete` method. We can also check whether `x` is a valid JuMP variable in `model` using the `JuMP.is_valid` method: ```jldoctest variables_delete From 176170f5d2fd6f0c8c2a00df40574480830e1659 Mon Sep 17 00:00:00 2001 From: odow Date: Thu, 23 Aug 2018 16:33:40 +1200 Subject: [PATCH 02/11] Add quickstart documentation --- .travis.yml | 2 +- docs/src/quickstart.md | 138 ++++++++++++++++++++++++++++++++++++++++- 2 files changed, 138 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 849e45c3442..06c11990198 100644 --- a/.travis.yml +++ b/.travis.yml @@ -21,5 +21,5 @@ addons: after_success: - echo $TRAVIS_JULIA_VERSION - julia -e 'Pkg.add("Coverage"); cd(Pkg.dir("JuMP")); using Coverage; Coveralls.submit(process_folder()); Codecov.submit(process_folder())' - - julia -e 'Pkg.add("Documenter")' + - julia -e 'Pkg.add("Documenter"); Pkg.add("GLPK")' - julia -e 'cd(Pkg.dir("JuMP")); include(joinpath("docs", "make.jl"))' diff --git a/docs/src/quickstart.md b/docs/src/quickstart.md index 81d383abac0..90477c382fe 100644 --- a/docs/src/quickstart.md +++ b/docs/src/quickstart.md @@ -1,4 +1,140 @@ Quick Start Guide ================= -TODO: Quick example of solving an LP and getting the solution back. +This quick start guide will introduce the main concepts of JuMP. If you are +familiar with another modeling language embedded in a high-level language such +as PuLP (Python) or a solver-specific interface you will find most of this +familiar, with the exception of *macros*. A deep understanding of macros is not +essential, but if you would like to know more please see the +[Julia documentation](http://docs.julialang.org/en/latest/manual/metaprogramming/). +If you are coming from an AMPL or similar background, you may find some of the +concepts novel but the general appearance will still be familiar. + +There are more complex examples in the [`JuMP/examples/` folder](https://github.com/JuliaOpt/JuMP.jl/tree/master/examples). + +Once JuMP is installed, to use JuMP in your programs, you just need to say: +```jldoctest quickstart_example +julia> using JuMP +``` + +We also need to include a Julia package which provides an appropriate solver. In +this case, we will use GLPK: +```jldoctest quickstart_example +julia> using GLPK +``` + +Models are created with the `Model()` function. The `with_optimizer` syntax is +used to specify the optimizer to be used: +```jldoctest quickstart_example +julia> model = Model(with_optimizer(GLPK.Optimizer)) +A JuMP Model +``` +!!! note + Your model doesn't have to be called `model` - it's just a name. However, + the JuMP style guide prefers `model`. + +There are a few options for defining a variable, depending on whether you want +to have lower bounds, upper bounds, both bounds, or even no bounds. The +following commands will create two variables, `x` and `y`, with both lower and +upper bounds. Note the first argument is our model variable ``model``. These +variables are associated with this model and cannot be used in another model. +```jldoctest quickstart_example +julia> @variable(model, 0 <= x <= 2) +x + +julia> @variable(model, 0 <= y <= 30) +y +``` +See the [Variables](@ref) section for more information on creating variables. + +Next we'll set our objective. Note again the `model`, so we know which model's +objective we are setting! The objective sense, `Max` or `Min`, should be +provided as the second argument. Note also that we don't have a multiplication +`*` symbol between `5` and our variable `x` - Julia is smart enough to not need +it! Feel free to stick with `*` if it makes you feel more comfortable, as we +have done with `3*y`: +```jldoctest quickstart_example +julia> @objective(model, Max, 5x + 3*y) +``` + +Adding constraints is a lot like setting the objective. Here we create a +less-than-or-equal-to constraint using `<=`, but we can also create equality +constraints using `==` and greater-than-or-equal-to constraints with `>=`: +```jldoctest quickstart_example +julia> con = @constraint(model, 1x + 5y <= 3) +x + 5 y <= 3.0 +``` +Note that we bind the constraint to the Julia variable `con` for later analysis. + +Models are solved with the `JuMP.optimize` function: +```jldoctest quickstart_example +julia> JuMP.optimize(model) +``` + +After the call to `JuMP.optimize` has finished, we need to understand why the +optimizer stopped. This can be for a number of reasons. First, the solver might +have found the optimal solution, or proved that the problem is infeasible. +However, it might also have run into numerical difficulties, or terminated due +to a setting such as a time limit. We can ask the solver why it stopped using +the `JuMP.terminationstatus` function: +```jldoctest quickstart_example +julia> JuMP.terminationstatus(model) +Success::MathOptInterface.TerminationStatusCode = 0 +``` +In this case, `GLPK` returned `Success`. This does not mean that it has found +the optimal solution. Instead, it indicates that GLPK has finished running and +did not encounter any errors or termination limits. + +To understand the reason for termination in more detail, we need to query +`JuMP.primalstatus`: +```jldoctest quickstart_example +julia> JuMP.primalstatus(model) +FeasiblePoint::MathOptInterface.ResultStatusCode = 0 +``` +This indicates that GLPK has found a `FeasiblePoint` to the primal problem. +Coupled with the `Success` from `JuMP.terminationstatus`, we can infer that GLPK +has indeed found the optimal solution. We can also query `JuMP.dualstatus`: +```jldoctest quickstart_example +julia> JuMP.dualstatus(model) +FeasiblePoint::MathOptInterface.ResultStatusCode = 0 +``` +Like the `primalstatus`, GLPK indicates that it has found a `FeasiblePoint` to +the dual problem. + +Finally, we can query the result of the optimization. First, we can query the +objective value: +```jldoctest quickstart_example +julia> JuMP.objectivevalue(model) +10.6 +``` +We can also query the primal result values of the `x` and `y` variables: +```jldoctest quickstart_example +julia> JuMP.resultvalue(x) +2.0 + +julia> JuMP.resultvalue(y) +0.2 +``` + +We can also query the value of the dual variable associated with the constraint +`con` (which we bound to a Julia variable when defining the constraint): +```jldoctest quickstart_example +julia> JuMP.resultdual(con) +-0.6 +``` + +To query the dual variables associated with the variable bounds, things are a +little trickier as we first need to obtain a reference to the constraint: +```jldoctest quickstart_example +julia> x_upper = JuMP.UpperBoundRef(x) +x <= 2.0 + +julia> JuMP.resultdual(x_upper) +-4.4 + +julia> y_lower = JuMP.LowerBoundRef(y) +y >= 0.0 + +julia> JuMP.resultdual(y_lower) +0.0 +``` From beab8d1044fcb15eab7eeafc798578d32fee6064 Mon Sep 17 00:00:00 2001 From: odow Date: Fri, 24 Aug 2018 14:07:03 +1200 Subject: [PATCH 03/11] Remove GLPK dependency --- .travis.yml | 2 +- docs/src/quickstart.md | 41 +++++++++++++++++++++++++++++++++++++++-- 2 files changed, 40 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 06c11990198..849e45c3442 100644 --- a/.travis.yml +++ b/.travis.yml @@ -21,5 +21,5 @@ addons: after_success: - echo $TRAVIS_JULIA_VERSION - julia -e 'Pkg.add("Coverage"); cd(Pkg.dir("JuMP")); using Coverage; Coveralls.submit(process_folder()); Codecov.submit(process_folder())' - - julia -e 'Pkg.add("Documenter"); Pkg.add("GLPK")' + - julia -e 'Pkg.add("Documenter")' - julia -e 'cd(Pkg.dir("JuMP")); include(joinpath("docs", "make.jl"))' diff --git a/docs/src/quickstart.md b/docs/src/quickstart.md index 90477c382fe..951d7f73b43 100644 --- a/docs/src/quickstart.md +++ b/docs/src/quickstart.md @@ -19,16 +19,27 @@ julia> using JuMP We also need to include a Julia package which provides an appropriate solver. In this case, we will use GLPK: -```jldoctest quickstart_example +```julia julia> using GLPK ``` Models are created with the `Model()` function. The `with_optimizer` syntax is used to specify the optimizer to be used: -```jldoctest quickstart_example +```julia julia> model = Model(with_optimizer(GLPK.Optimizer)) A JuMP Model ``` + +```@meta +DocTestSetup = quote + # Using a caching optimizer removes the need to # load a solver such as GLPK + # for building the documentation. + const MOI = JuMP.MathOptInterface + model = Model(with_optimizer(MOI.Utilities.MockOptimizer, + JuMP.JuMPMOIModel{Float64}(), + evalobjective=false)) +end +``` !!! note Your model doesn't have to be called `model` - it's just a name. However, the JuMP style guide prefers `model`. @@ -47,6 +58,10 @@ y ``` See the [Variables](@ref) section for more information on creating variables. +```@meta +DocTestSetup = nothing +``` + Next we'll set our objective. Note again the `model`, so we know which model's objective we are setting! The objective sense, `Max` or `Min`, should be provided as the second argument. Note also that we don't have a multiplication @@ -71,6 +86,24 @@ Models are solved with the `JuMP.optimize` function: julia> JuMP.optimize(model) ``` +```@meta +DocTestSetup = quote + # Now we load in the solution. Using a caching optimizer removes the need to + # load a solver such as GLPK for building the documentation. + mock = JuMP.caching_optimizer(model).optimizer + MOI.set!(mock, MOI.TerminationStatus(), MOI.Success) + MOI.set!(mock, MOI.PrimalStatus(), MOI.FeasiblePoint) + MOI.set!(mock, MOI.DualStatus(), MOI.FeasiblePoint) + MOI.set!(mock, MOI.ResultCount(), 1) + MOI.set!(mock, MOI.ObjectiveValue(), 10.6) + MOI.set!(mock, MOI.VariablePrimal(), JuMP.optimizerindex(x), 2.0) + MOI.set!(mock, MOI.VariablePrimal(), JuMP.optimizerindex(y), 0.2) + MOI.set!(mock, MOI.ConstraintDual(), JuMP.optimizerindex(con), -0.6) + MOI.set!(mock, MOI.ConstraintDual(), JuMP.optimizerindex(JuMP.UpperBoundRef(x)), -4.4) + MOI.set!(mock, MOI.ConstraintDual(), JuMP.optimizerindex(JuMP.LowerBoundRef(y)), 0.0) +end +``` + After the call to `JuMP.optimize` has finished, we need to understand why the optimizer stopped. This can be for a number of reasons. First, the solver might have found the optimal solution, or proved that the problem is infeasible. @@ -85,6 +118,10 @@ In this case, `GLPK` returned `Success`. This does not mean that it has found the optimal solution. Instead, it indicates that GLPK has finished running and did not encounter any errors or termination limits. +```@meta +DocTestSetup = nothing +``` + To understand the reason for termination in more detail, we need to query `JuMP.primalstatus`: ```jldoctest quickstart_example From c9f7d6d1a054f3d81608096b9a539e25a2d3896b Mon Sep 17 00:00:00 2001 From: odow Date: Fri, 24 Aug 2018 14:13:06 +1200 Subject: [PATCH 04/11] Filter comparison operators --- docs/src/quickstart.md | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/docs/src/quickstart.md b/docs/src/quickstart.md index 951d7f73b43..4caad72738f 100644 --- a/docs/src/quickstart.md +++ b/docs/src/quickstart.md @@ -75,7 +75,7 @@ julia> @objective(model, Max, 5x + 3*y) Adding constraints is a lot like setting the objective. Here we create a less-than-or-equal-to constraint using `<=`, but we can also create equality constraints using `==` and greater-than-or-equal-to constraints with `>=`: -```jldoctest quickstart_example +```jldoctest quickstart_example; filter=r"≤|<=" julia> con = @constraint(model, 1x + 5y <= 3) x + 5 y <= 3.0 ``` @@ -162,13 +162,16 @@ julia> JuMP.resultdual(con) To query the dual variables associated with the variable bounds, things are a little trickier as we first need to obtain a reference to the constraint: -```jldoctest quickstart_example +```jldoctest quickstart_example; filter=r"≤|<=" julia> x_upper = JuMP.UpperBoundRef(x) x <= 2.0 julia> JuMP.resultdual(x_upper) -4.4 - +``` +A similar process can be followed to obtain the dual of the lower bound +constraint on `y`: +```jldoctest quickstart_example; filter=r"≥|>=" julia> y_lower = JuMP.LowerBoundRef(y) y >= 0.0 From d0fed02bdf78aa3acc55f657802dbb14d6b341b0 Mon Sep 17 00:00:00 2001 From: odow Date: Sat, 25 Aug 2018 10:41:07 +1200 Subject: [PATCH 05/11] Filter our JuMP. and fix minor typos --- docs/src/quickstart.md | 2 ++ docs/src/variables.md | 11 ++++++----- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/docs/src/quickstart.md b/docs/src/quickstart.md index 4caad72738f..d731c7c43af 100644 --- a/docs/src/quickstart.md +++ b/docs/src/quickstart.md @@ -39,6 +39,8 @@ DocTestSetup = quote JuMP.JuMPMOIModel{Float64}(), evalobjective=false)) end +# v0.6 prepends JuMP. to printed type information, whereas v0.7 does not. +DocTestFilters = r"JuMP\." ``` !!! note Your model doesn't have to be called `model` - it's just a name. However, diff --git a/docs/src/variables.md b/docs/src/variables.md index 5d2006a38d6..97f56598ec0 100644 --- a/docs/src/variables.md +++ b/docs/src/variables.md @@ -3,6 +3,7 @@ CurrentModule = JuMP DocTestSetup = quote using JuMP end +DocTestFilters = r"JuMP\." ``` Variables @@ -69,8 +70,8 @@ julia> y decision variable ``` -Because `y` is a Julia variable, I can bind it to a different value. For example, -if I go: +Because `y` is a JuMP variable, we can bind it to a different value. For +example, if we go: ```jldoctest variables julia> y = 1 1 @@ -134,9 +135,9 @@ In the above examples, `x_free` represents an unbounded optimization variable, `@variable(model, a <= x)`) will result in an error. **Extra for experts:** the reason for this is that at compile time, JuMP - does not type and value information. Therefore, the case `@variable(model, - a <= b)` is ambiguous as JuMP cannot infer whether `a` is a constant and - `b` is the intended variable name, or vice-versa. + does not have type and value information. Therefore, the case + `@variable(model, a <= b)` is ambiguous as JuMP cannot infer whether `a` is + a constant and `b` is the intended variable name, or vice-versa. We can query whether an optimization variable has a lower- or upper-bound via the `JuMP.has_lower_bound` and `JuMP.has_upper_bound` functions. For example: From 5825e8ff0098462142b4680a57e053265323ebcf Mon Sep 17 00:00:00 2001 From: odow Date: Mon, 27 Aug 2018 16:07:50 +1200 Subject: [PATCH 06/11] Remove macro reference and other small style fixes --- docs/src/quickstart.md | 30 +++++++++++++++--------------- docs/src/variables.md | 4 +++- 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/docs/src/quickstart.md b/docs/src/quickstart.md index d731c7c43af..0b443c76b28 100644 --- a/docs/src/quickstart.md +++ b/docs/src/quickstart.md @@ -4,24 +4,24 @@ Quick Start Guide This quick start guide will introduce the main concepts of JuMP. If you are familiar with another modeling language embedded in a high-level language such as PuLP (Python) or a solver-specific interface you will find most of this -familiar, with the exception of *macros*. A deep understanding of macros is not -essential, but if you would like to know more please see the -[Julia documentation](http://docs.julialang.org/en/latest/manual/metaprogramming/). -If you are coming from an AMPL or similar background, you may find some of the -concepts novel but the general appearance will still be familiar. +familiar. If you are coming from an AMPL or similar background, you may find +some of the concepts novel but the general appearance will still be familiar. -There are more complex examples in the [`JuMP/examples/` folder](https://github.com/JuliaOpt/JuMP.jl/tree/master/examples). +The example in this guide is deliberately kept simple. There are more complex +examples in the [`JuMP/examples/` folder](https://github.com/JuliaOpt/JuMP.jl/tree/master/examples). Once JuMP is installed, to use JuMP in your programs, you just need to say: ```jldoctest quickstart_example julia> using JuMP ``` -We also need to include a Julia package which provides an appropriate solver. In -this case, we will use GLPK: +You also need to include a Julia package which provides an appropriate solver. +One such solver is `GLPK.Optimizer`, which is provided by the +[GLPK.jl package](https://github.com/JuliaOpt/GLPK.jl). ```julia julia> using GLPK ``` +See [Installation Guide](@ref) for a list of other solvers you can use. Models are created with the `Model()` function. The `with_optimizer` syntax is used to specify the optimizer to be used: @@ -39,12 +39,12 @@ DocTestSetup = quote JuMP.JuMPMOIModel{Float64}(), evalobjective=false)) end -# v0.6 prepends JuMP. to printed type information, whereas v0.7 does not. -DocTestFilters = r"JuMP\." +# v0.6 prepends the module name to printed type information, whereas v0.7 does +# not. +DocTestFilters = [r"JuMP\.", r"MathOptInterface\."] ``` !!! note - Your model doesn't have to be called `model` - it's just a name. However, - the JuMP style guide prefers `model`. + Your model doesn't have to be called `model` - it's just a name. There are a few options for defining a variable, depending on whether you want to have lower bounds, upper bounds, both bounds, or even no bounds. The @@ -69,9 +69,9 @@ objective we are setting! The objective sense, `Max` or `Min`, should be provided as the second argument. Note also that we don't have a multiplication `*` symbol between `5` and our variable `x` - Julia is smart enough to not need it! Feel free to stick with `*` if it makes you feel more comfortable, as we -have done with `3*y`: +have done with `3 * y`: ```jldoctest quickstart_example -julia> @objective(model, Max, 5x + 3*y) +julia> @objective(model, Max, 5x + 3 * y) ``` Adding constraints is a lot like setting the objective. Here we create a @@ -118,7 +118,7 @@ Success::MathOptInterface.TerminationStatusCode = 0 ``` In this case, `GLPK` returned `Success`. This does not mean that it has found the optimal solution. Instead, it indicates that GLPK has finished running and -did not encounter any errors or termination limits. +did not encounter any errors or user-provided termination limits. ```@meta DocTestSetup = nothing diff --git a/docs/src/variables.md b/docs/src/variables.md index 97f56598ec0..d6691c0b56a 100644 --- a/docs/src/variables.md +++ b/docs/src/variables.md @@ -3,7 +3,9 @@ CurrentModule = JuMP DocTestSetup = quote using JuMP end -DocTestFilters = r"JuMP\." +# v0.6 prepends the module name to printed type information, whereas v0.7 does +# not. +DocTestFilters = [r"JuMP\.", r"MathOptInterface\.", r"LinearAlgebra\."] ``` Variables From d67ca11a59d9df3f2e7a049028f902d1980b891f Mon Sep 17 00:00:00 2001 From: odow Date: Thu, 30 Aug 2018 11:07:49 +1200 Subject: [PATCH 07/11] Update for JuMP renaming --- docs/src/quickstart.md | 44 +++++++++++++++++++++--------------------- docs/src/variables.md | 40 +++++++++++++++++++------------------- 2 files changed, 42 insertions(+), 42 deletions(-) diff --git a/docs/src/quickstart.md b/docs/src/quickstart.md index 0b443c76b28..1154ff43dd1 100644 --- a/docs/src/quickstart.md +++ b/docs/src/quickstart.md @@ -83,9 +83,9 @@ x + 5 y <= 3.0 ``` Note that we bind the constraint to the Julia variable `con` for later analysis. -Models are solved with the `JuMP.optimize` function: +Models are solved with the `JuMP.optimize!` function: ```jldoctest quickstart_example -julia> JuMP.optimize(model) +julia> JuMP.optimize!(model) ``` ```@meta @@ -98,22 +98,22 @@ DocTestSetup = quote MOI.set!(mock, MOI.DualStatus(), MOI.FeasiblePoint) MOI.set!(mock, MOI.ResultCount(), 1) MOI.set!(mock, MOI.ObjectiveValue(), 10.6) - MOI.set!(mock, MOI.VariablePrimal(), JuMP.optimizerindex(x), 2.0) - MOI.set!(mock, MOI.VariablePrimal(), JuMP.optimizerindex(y), 0.2) - MOI.set!(mock, MOI.ConstraintDual(), JuMP.optimizerindex(con), -0.6) - MOI.set!(mock, MOI.ConstraintDual(), JuMP.optimizerindex(JuMP.UpperBoundRef(x)), -4.4) - MOI.set!(mock, MOI.ConstraintDual(), JuMP.optimizerindex(JuMP.LowerBoundRef(y)), 0.0) + MOI.set!(mock, MOI.VariablePrimal(), JuMP.optimizer_index(x), 2.0) + MOI.set!(mock, MOI.VariablePrimal(), JuMP.optimizer_index(y), 0.2) + MOI.set!(mock, MOI.ConstraintDual(), JuMP.optimizer_index(con), -0.6) + MOI.set!(mock, MOI.ConstraintDual(), JuMP.optimizer_index(JuMP.UpperBoundRef(x)), -4.4) + MOI.set!(mock, MOI.ConstraintDual(), JuMP.optimizer_index(JuMP.LowerBoundRef(y)), 0.0) end ``` -After the call to `JuMP.optimize` has finished, we need to understand why the +After the call to `JuMP.optimize!` has finished, we need to understand why the optimizer stopped. This can be for a number of reasons. First, the solver might have found the optimal solution, or proved that the problem is infeasible. However, it might also have run into numerical difficulties, or terminated due to a setting such as a time limit. We can ask the solver why it stopped using -the `JuMP.terminationstatus` function: +the `JuMP.termination_status` function: ```jldoctest quickstart_example -julia> JuMP.terminationstatus(model) +julia> JuMP.termination_status(model) Success::MathOptInterface.TerminationStatusCode = 0 ``` In this case, `GLPK` returned `Success`. This does not mean that it has found @@ -127,38 +127,38 @@ DocTestSetup = nothing To understand the reason for termination in more detail, we need to query `JuMP.primalstatus`: ```jldoctest quickstart_example -julia> JuMP.primalstatus(model) +julia> JuMP.primal_status(model) FeasiblePoint::MathOptInterface.ResultStatusCode = 0 ``` This indicates that GLPK has found a `FeasiblePoint` to the primal problem. -Coupled with the `Success` from `JuMP.terminationstatus`, we can infer that GLPK -has indeed found the optimal solution. We can also query `JuMP.dualstatus`: +Coupled with the `Success` from `JuMP.termination_status`, we can infer that GLPK +has indeed found the optimal solution. We can also query `JuMP.dual_status`: ```jldoctest quickstart_example -julia> JuMP.dualstatus(model) +julia> JuMP.dual_status(model) FeasiblePoint::MathOptInterface.ResultStatusCode = 0 ``` -Like the `primalstatus`, GLPK indicates that it has found a `FeasiblePoint` to -the dual problem. +Like the `primal_status`, GLPK indicates that it has found a `FeasiblePoint` to +the dual problem. Finally, we can query the result of the optimization. First, we can query the objective value: ```jldoctest quickstart_example -julia> JuMP.objectivevalue(model) +julia> JuMP.objective_value(model) 10.6 ``` We can also query the primal result values of the `x` and `y` variables: ```jldoctest quickstart_example -julia> JuMP.resultvalue(x) +julia> JuMP.result_value(x) 2.0 -julia> JuMP.resultvalue(y) +julia> JuMP.result_value(y) 0.2 ``` We can also query the value of the dual variable associated with the constraint `con` (which we bound to a Julia variable when defining the constraint): ```jldoctest quickstart_example -julia> JuMP.resultdual(con) +julia> JuMP.result_dual(con) -0.6 ``` @@ -168,7 +168,7 @@ little trickier as we first need to obtain a reference to the constraint: julia> x_upper = JuMP.UpperBoundRef(x) x <= 2.0 -julia> JuMP.resultdual(x_upper) +julia> JuMP.result_dual(x_upper) -4.4 ``` A similar process can be followed to obtain the dual of the lower bound @@ -177,6 +177,6 @@ constraint on `y`: julia> y_lower = JuMP.LowerBoundRef(y) y >= 0.0 -julia> JuMP.resultdual(y_lower) +julia> JuMP.result_dual(y_lower) 0.0 ``` diff --git a/docs/src/variables.md b/docs/src/variables.md index d6691c0b56a..90d18b4a740 100644 --- a/docs/src/variables.md +++ b/docs/src/variables.md @@ -133,13 +133,13 @@ In the above examples, `x_free` represents an unbounded optimization variable, !!! note When creating a variable with only a lower-bound or an upper-bound, and the value of the bound is not a numeric literal, the name must appear on the - left-hand side. Putting the name on the right-hand side (e.g., `a=1`, - `@variable(model, a <= x)`) will result in an error. - - **Extra for experts:** the reason for this is that at compile time, JuMP - does not have type and value information. Therefore, the case - `@variable(model, a <= b)` is ambiguous as JuMP cannot infer whether `a` is - a constant and `b` is the intended variable name, or vice-versa. + left-hand side. Putting the name on the right-hand side will result in an + error. For example: + ```julia + @variable(model, 1 <= x) # works + a = 1 + @variable(model, a <= x) # errors + ``` We can query whether an optimization variable has a lower- or upper-bound via the `JuMP.has_lower_bound` and `JuMP.has_upper_bound` functions. For example: @@ -172,42 +172,42 @@ julia> JuMP.lower_bound(x) 1.0 ``` -Another option is to use the `JuMP.setlowerbound` and `JuMP.setupperbound` +Another option is to use the `JuMP.set_lower_bound` and `JuMP.set_upper_bound` functions. These can also be used to modify an existing variable bound. For example: ```jldoctest; setup=:(model=Model()) julia> @variable(model, x >= 1) x -julia> JuMP.lowerbound(x) +julia> JuMP.lower_bound(x) 1.0 -julia> JuMP.setlowerbound(x, 2) +julia> JuMP.set_lower_bound(x, 2) -julia> JuMP.lowerbound(x) +julia> JuMP.lower_bound(x) 2.0 ``` -Finally, we can delete variable bounds using `JuMP.deletelowerbound` and -`JuMP.deleteupperbound`: +Finally, we can delete variable bounds using `JuMP.delete_lower_bound` and +`JuMP.delete_upper_bound`: ```jldoctest; setup=:(model=Model()) julia> @variable(model, 1 <= x <= 2) x -julia> JuMP.lowerbound(x) +julia> JuMP.lower_bound(x) 1.0 -julia> JuMP.deletelowerbound(x) +julia> JuMP.delete_lower_bound(x) -julia> JuMP.haslowerbound(x) +julia> JuMP.has_lower_bound(x) false -julia> JuMP.upperbound(x) +julia> JuMP.upper_bound(x) 2.0 -julia> JuMP.deleteupperbound(x) +julia> JuMP.delete_upper_bound(x) -julia> JuMP.hasupperbound(x) +julia> JuMP.has_upper_bound(x) false ``` @@ -515,7 +515,7 @@ Dict{Symbol,Symmetric{JuMP.VariableRef,Array{JuMP.VariableRef,2}}} with 2 entrie JuMP supports the deletion of optimization variables. To delete variables, we can use the `JuMP.delete` method. We can also check whether `x` is a valid JuMP variable in `model` using the `JuMP.is_valid` method: -```jldoctest variables_delete +```jldoctest variables_delete; setup=:(model=Model()) julia> @variable(model, x) x From fa038e1f566fa445515a9788f5415e53a343e314 Mon Sep 17 00:00:00 2001 From: odow Date: Sat, 1 Sep 2018 18:35:20 +1200 Subject: [PATCH 08/11] Remove doctest filters --- docs/src/quickstart.md | 3 --- docs/src/variables.md | 3 --- 2 files changed, 6 deletions(-) diff --git a/docs/src/quickstart.md b/docs/src/quickstart.md index 1154ff43dd1..fbafef0279c 100644 --- a/docs/src/quickstart.md +++ b/docs/src/quickstart.md @@ -39,9 +39,6 @@ DocTestSetup = quote JuMP.JuMPMOIModel{Float64}(), evalobjective=false)) end -# v0.6 prepends the module name to printed type information, whereas v0.7 does -# not. -DocTestFilters = [r"JuMP\.", r"MathOptInterface\."] ``` !!! note Your model doesn't have to be called `model` - it's just a name. diff --git a/docs/src/variables.md b/docs/src/variables.md index 90d18b4a740..1ae6b65ac19 100644 --- a/docs/src/variables.md +++ b/docs/src/variables.md @@ -3,9 +3,6 @@ CurrentModule = JuMP DocTestSetup = quote using JuMP end -# v0.6 prepends the module name to printed type information, whereas v0.7 does -# not. -DocTestFilters = [r"JuMP\.", r"MathOptInterface\.", r"LinearAlgebra\."] ``` Variables From 1dac212887e3a316ad47e78effc80294ec68f542 Mon Sep 17 00:00:00 2001 From: odow Date: Sun, 2 Sep 2018 18:23:43 +1200 Subject: [PATCH 09/11] Move documenter to run on v1.0 --- .travis.yml | 6 ++--- docs/make.jl | 2 +- docs/src/quickstart.md | 6 ++--- docs/src/variables.md | 51 +++++++++++++++++++++--------------------- 4 files changed, 32 insertions(+), 33 deletions(-) diff --git a/.travis.yml b/.travis.yml index 849e45c3442..f9582d14877 100644 --- a/.travis.yml +++ b/.travis.yml @@ -20,6 +20,6 @@ addons: - libblas-dev after_success: - echo $TRAVIS_JULIA_VERSION - - julia -e 'Pkg.add("Coverage"); cd(Pkg.dir("JuMP")); using Coverage; Coveralls.submit(process_folder()); Codecov.submit(process_folder())' - - julia -e 'Pkg.add("Documenter")' - - julia -e 'cd(Pkg.dir("JuMP")); include(joinpath("docs", "make.jl"))' + - julia -e '(VERSION >= v"0.7" && using Pkg); Pkg.add("Coverage"); cd(Pkg.dir("JuMP")); using Coverage; Coveralls.submit(process_folder()); Codecov.submit(process_folder())' + - julia -e '(VERSION >= v"0.7" && using Pkg); Pkg.add("Documenter")' + - julia -e 'VERSION == v"1.0" && (using Pkg; cd(Pkg.dir("JuMP")); include(joinpath("docs", "make.jl")))' diff --git a/docs/make.jl b/docs/make.jl index 45c47540d32..08de87a6503 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -32,7 +32,7 @@ deploydocs( repo = "github.com/JuliaOpt/JuMP.jl.git", target = "build", osname = "linux", - julia = "0.6", + julia = "1.0", deps = nothing, make = nothing ) diff --git a/docs/src/quickstart.md b/docs/src/quickstart.md index fbafef0279c..cd3d3132392 100644 --- a/docs/src/quickstart.md +++ b/docs/src/quickstart.md @@ -111,7 +111,7 @@ to a setting such as a time limit. We can ask the solver why it stopped using the `JuMP.termination_status` function: ```jldoctest quickstart_example julia> JuMP.termination_status(model) -Success::MathOptInterface.TerminationStatusCode = 0 +Success::TerminationStatusCode = 0 ``` In this case, `GLPK` returned `Success`. This does not mean that it has found the optimal solution. Instead, it indicates that GLPK has finished running and @@ -125,14 +125,14 @@ To understand the reason for termination in more detail, we need to query `JuMP.primalstatus`: ```jldoctest quickstart_example julia> JuMP.primal_status(model) -FeasiblePoint::MathOptInterface.ResultStatusCode = 0 +FeasiblePoint::ResultStatusCode = 0 ``` This indicates that GLPK has found a `FeasiblePoint` to the primal problem. Coupled with the `Success` from `JuMP.termination_status`, we can infer that GLPK has indeed found the optimal solution. We can also query `JuMP.dual_status`: ```jldoctest quickstart_example julia> JuMP.dual_status(model) -FeasiblePoint::MathOptInterface.ResultStatusCode = 0 +FeasiblePoint::ResultStatusCode = 0 ``` Like the `primal_status`, GLPK indicates that it has found a `FeasiblePoint` to the dual problem. diff --git a/docs/src/variables.md b/docs/src/variables.md index 1ae6b65ac19..bb20ae2cf50 100644 --- a/docs/src/variables.md +++ b/docs/src/variables.md @@ -30,7 +30,7 @@ julia> model = Model() A JuMP Model julia> @variable(model, x[1:2]) -2-element Array{JuMP.VariableRef,1}: +2-element Array{VariableRef,1}: x[1] x[2] ``` @@ -226,7 +226,7 @@ We have already seen the creation of an array of JuMP variables with the arrays of JuMP variables. For example: ```jldoctest variables_arrays; setup=:(model=Model()) julia> @variable(model, x[1:2, 1:2]) -2×2 Array{JuMP.VariableRef,2}: +2×2 Array{VariableRef,2}: x[1,1] x[1,2] x[2,1] x[2,2] ``` @@ -237,7 +237,7 @@ julia> x[1, 2] x[1,2] julia> x[2, :] -2-element Array{JuMP.VariableRef,1}: +2-element Array{VariableRef,1}: x[2,1] x[2,2] ``` @@ -245,7 +245,7 @@ julia> x[2, :] We can also name each index, and variable bounds can depend upon the indices: ```jldoctest; setup=:(model=Model()) julia> @variable(model, x[i=1:2, j=1:2] >= 2i + j) -2×2 Array{JuMP.VariableRef,2}: +2×2 Array{VariableRef,2}: x[1,1] x[1,2] x[2,1] x[2,2] @@ -269,10 +269,10 @@ difference is that instead of returning an `Array` of JuMP variables, JuMP will return a `JuMPArray`. For example: ```jldoctest variables_jump_arrays; setup=:(model=Model()) julia> @variable(model, x[1:2, [:A,:B]]) -2-dimensional JuMPArray{JuMP.VariableRef,2,...} with index sets: +2-dimensional JuMPArray{VariableRef,2,...} with index sets: Dimension 1, 1:2 Dimension 2, Symbol[:A, :B] -And data, a 2×2 Array{JuMP.VariableRef,2}: +And data, a 2×2 Array{VariableRef,2}: x[1,A] x[1,B] x[2,A] x[2,B] ``` @@ -283,9 +283,9 @@ julia> x[1, :A] x[1,A] julia> x[2, :] -1-dimensional JuMPArray{JuMP.VariableRef,1,...} with index sets: +1-dimensional JuMPArray{VariableRef,1,...} with index sets: Dimension 1, Symbol[:A, :B] -And data, a 2-element Array{JuMP.VariableRef,1}: +And data, a 2-element Array{VariableRef,1}: x[2,A] x[2,B] ``` @@ -294,10 +294,10 @@ Similarly to the `Array` case, the indices in a `JuMPArray` can be named, and the bounds can depend upon these names. For example: ```jldoctest; setup=:(model=Model()) julia> @variable(model, x[i=2:3, j=1:2:3] >= 0.5i + j) -2-dimensional JuMPArray{JuMP.VariableRef,2,...} with index sets: +2-dimensional JuMPArray{VariableRef,2,...} with index sets: Dimension 1, 2:3 Dimension 2, 1:2:3 -And data, a 2×2 Array{JuMP.VariableRef,2}: +And data, a 2×2 Array{VariableRef,2}: x[2,1] x[2,3] x[3,1] x[3,3] @@ -318,7 +318,7 @@ rectangular set. One example is 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]) -Dict{Any,JuMP.VariableRef} with 3 entries: +Dict{Any,VariableRef} with 3 entries: (1, 2) => x[1,2] (2, 2) => x[2,2] (1, 1) => x[1,1] @@ -330,7 +330,7 @@ sytax 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]) -Dict{Any,JuMP.VariableRef} with 2 entries: +Dict{Any,VariableRef} with 2 entries: 4 => x[4] 2 => x[2] ``` @@ -347,9 +347,9 @@ julia> A = 1:2 1:2 julia> @variable(model, x[A]) -1-dimensional JuMPArray{JuMP.VariableRef,1,...} with index sets: +1-dimensional JuMPArray{VariableRef,1,...} with index sets: Dimension 1, 1:2 -And data, a 2-element Array{JuMP.VariableRef,1}: +And data, a 2-element Array{VariableRef,1}: x[1] x[2] ``` @@ -362,7 +362,7 @@ We can share our knowledge that it is possible to store these JuMP variables as an array by setting the `container` keyword: ```jldoctest variable_force_container julia> @variable(model, y[A], container=Array) -2-element Array{JuMP.VariableRef,1}: +2-element Array{VariableRef,1}: y[1] y[2] ``` @@ -426,7 +426,7 @@ matrix ``X`` is positive semidefinite if all eigenvalues are nonnegative. We can declare a matrix of JuMP variables to be positive semidefinite as follows: ```jldoctest; setup=:(model=Model()) julia> @variable(model, x[1:2, 1:2], PSD) -2×2 Symmetric{JuMP.VariableRef,Array{JuMP.VariableRef,2}}: +2×2 LinearAlgebra.Symmetric{VariableRef,Array{VariableRef,2}}: x[1,1] x[1,2] x[1,2] x[2,2] ``` @@ -439,7 +439,7 @@ You can also impose a slightly weaker constraint that the square matrix is only symmetric (instead of positive semidefinite) as follows: ```jldoctest; setup=:(model=Model()) julia> @variable(model, x[1:2, 1:2], Symmetric) -2×2 Symmetric{JuMP.VariableRef,Array{JuMP.VariableRef,2}}: +2×2 LinearAlgebra.Symmetric{VariableRef,Array{VariableRef,2}}: x[1,1] x[1,2] x[1,2] x[2,2] ``` @@ -463,7 +463,7 @@ x An `Array` of anonymous JuMP variables can be created as follows: ```jldoctest; setup=:(model=Model()) julia> y = @variable(model, [i=1:2]) -2-element Array{JuMP.VariableRef,1}: +2-element Array{VariableRef,1}: noname noname ``` @@ -480,7 +480,7 @@ use the `binary` and `integer` keywords. Thus, the anonymous variant of `@variable(model, x[i=1:2] >= i, Int)` is: ```jldoctest; setup=:(model=Model()) julia> x = @variable(model, [i=1:2], basename="x", lower_bound=i, integer=true) -2-element Array{JuMP.VariableRef,1}: +2-element Array{VariableRef,1}: x[1] x[2] ``` @@ -493,18 +493,17 @@ containers. However, users are also free to create collections of JuMP variables in their own datastructures. For example, the following code creates a dictionary with symmetric matrices as the values: ```jldoctest; setup=:(model=Model()) -julia> variables = Dict{Symbol, Symmetric{JuMP.VariableRef, - Array{JuMP.VariableRef,2}}}() -Dict{Symbol,Symmetric{JuMP.VariableRef,Array{JuMP.VariableRef,2}}} with 0 entries +julia> variables = Dict{Symbol, Array{VariableRef,2}}() +Dict{Symbol,Array{VariableRef,2}} with 0 entries julia> for key in [:A, :B] - variables[key] = @variable(model, [1:2, 1:2], Symmetric) + global variables[key] = @variable(model, [1:2, 1:2]) end julia> variables -Dict{Symbol,Symmetric{JuMP.VariableRef,Array{JuMP.VariableRef,2}}} with 2 entries: - :A => JuMP.VariableRef[noname noname; noname noname] - :B => JuMP.VariableRef[noname noname; noname noname] +Dict{Symbol,Array{VariableRef,2}} with 2 entries: + :A => VariableRef[noname noname; noname noname] + :B => VariableRef[noname noname; noname noname] ``` ## Deleting variables From 897d32ed3af62e9dd39383f034494c9ea8d7eafa Mon Sep 17 00:00:00 2001 From: odow Date: Sun, 2 Sep 2018 19:54:17 +1200 Subject: [PATCH 10/11] Rebase for MOI v0.6 --- docs/src/quickstart.md | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/docs/src/quickstart.md b/docs/src/quickstart.md index cd3d3132392..144086b07ad 100644 --- a/docs/src/quickstart.md +++ b/docs/src/quickstart.md @@ -37,7 +37,8 @@ DocTestSetup = quote const MOI = JuMP.MathOptInterface model = Model(with_optimizer(MOI.Utilities.MockOptimizer, JuMP.JuMPMOIModel{Float64}(), - evalobjective=false)) + eval_objective_value = false, + eval_variable_constraint_dual = false)) end ``` !!! note @@ -90,16 +91,16 @@ DocTestSetup = quote # Now we load in the solution. Using a caching optimizer removes the need to # load a solver such as GLPK for building the documentation. mock = JuMP.caching_optimizer(model).optimizer - MOI.set!(mock, MOI.TerminationStatus(), MOI.Success) - MOI.set!(mock, MOI.PrimalStatus(), MOI.FeasiblePoint) - MOI.set!(mock, MOI.DualStatus(), MOI.FeasiblePoint) - MOI.set!(mock, MOI.ResultCount(), 1) - MOI.set!(mock, MOI.ObjectiveValue(), 10.6) - MOI.set!(mock, MOI.VariablePrimal(), JuMP.optimizer_index(x), 2.0) - MOI.set!(mock, MOI.VariablePrimal(), JuMP.optimizer_index(y), 0.2) - MOI.set!(mock, MOI.ConstraintDual(), JuMP.optimizer_index(con), -0.6) - MOI.set!(mock, MOI.ConstraintDual(), JuMP.optimizer_index(JuMP.UpperBoundRef(x)), -4.4) - MOI.set!(mock, MOI.ConstraintDual(), JuMP.optimizer_index(JuMP.LowerBoundRef(y)), 0.0) + MOI.set(mock, MOI.TerminationStatus(), MOI.Success) + MOI.set(mock, MOI.PrimalStatus(), MOI.FeasiblePoint) + MOI.set(mock, MOI.DualStatus(), MOI.FeasiblePoint) + MOI.set(mock, MOI.ResultCount(), 1) + MOI.set(mock, MOI.ObjectiveValue(), 10.6) + MOI.set(mock, MOI.VariablePrimal(), JuMP.optimizer_index(x), 2.0) + MOI.set(mock, MOI.VariablePrimal(), JuMP.optimizer_index(y), 0.2) + MOI.set(mock, MOI.ConstraintDual(), JuMP.optimizer_index(con), -0.6) + MOI.set(mock, MOI.ConstraintDual(), JuMP.optimizer_index(JuMP.UpperBoundRef(x)), -4.4) + MOI.set(mock, MOI.ConstraintDual(), JuMP.optimizer_index(JuMP.LowerBoundRef(y)), 0.0) end ``` @@ -125,14 +126,14 @@ To understand the reason for termination in more detail, we need to query `JuMP.primalstatus`: ```jldoctest quickstart_example julia> JuMP.primal_status(model) -FeasiblePoint::ResultStatusCode = 0 +FeasiblePoint::ResultStatusCode = 1 ``` This indicates that GLPK has found a `FeasiblePoint` to the primal problem. Coupled with the `Success` from `JuMP.termination_status`, we can infer that GLPK has indeed found the optimal solution. We can also query `JuMP.dual_status`: ```jldoctest quickstart_example julia> JuMP.dual_status(model) -FeasiblePoint::ResultStatusCode = 0 +FeasiblePoint::ResultStatusCode = 1 ``` Like the `primal_status`, GLPK indicates that it has found a `FeasiblePoint` to the dual problem. From 2eb8a4661663689e72a7c7f3e349dbf342f575bc Mon Sep 17 00:00:00 2001 From: Oscar Dowson Date: Mon, 3 Sep 2018 09:40:43 +1200 Subject: [PATCH 11/11] Fix a mistake from rebasing --- docs/src/variables.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/variables.md b/docs/src/variables.md index bb20ae2cf50..8c3e7977ce8 100644 --- a/docs/src/variables.md +++ b/docs/src/variables.md @@ -69,7 +69,7 @@ julia> y decision variable ``` -Because `y` is a JuMP variable, we can bind it to a different value. For +Because `y` is a Julia variable, we can bind it to a different value. For example, if we go: ```jldoctest variables julia> y = 1