diff --git a/.github/workflows/documentation.yml b/.github/workflows/documentation.yml index d3ebd29f..3ed120bc 100644 --- a/.github/workflows/documentation.yml +++ b/.github/workflows/documentation.yml @@ -12,8 +12,7 @@ jobs: - uses: actions/checkout@v4 - uses: julia-actions/setup-julia@latest with: - # Build documentation on Julia 1.6 - version: '1.6' + version: '1.10' - name: Install dependencies run: julia --project=docs/ -e 'using Pkg; Pkg.develop(PackageSpec(path=pwd())); Pkg.instantiate()' - name: Build and deploy diff --git a/docs/Project.toml b/docs/Project.toml index 3a52a5db..55ac6c65 100644 --- a/docs/Project.toml +++ b/docs/Project.toml @@ -1,5 +1,11 @@ [deps] Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4" +HiGHS = "87dc4568-4c63-4d18-b0c0-bb2238e4078b" +Ipopt = "b6b21f68-93f8-5de0-b562-5493be1d77c9" +JuMP = "4076af6c-e467-56ae-b986-b466b2749572" +MathOptInterface = "b8f27783-ece8-5eb3-8dc8-9495eed66fee" +ParametricOptInterface = "0ce4ce61-57bf-432b-a095-efac525d185e" +Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80" [compat] -Documenter = "0.27" +Documenter = "1" diff --git a/docs/make.jl b/docs/make.jl index 894f8f19..7ec8d039 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -6,9 +6,8 @@ using Documenter using ParametricOptInterface -makedocs( +Documenter.makedocs(; modules = [ParametricOptInterface], - doctest = false, clean = true, # See https://github.com/JuliaDocs/Documenter.jl/issues/868 format = Documenter.HTML( @@ -28,9 +27,10 @@ makedocs( ], "reference.md", ], + checkdocs = :none, ) -deploydocs( +Documenter.deploydocs(; repo = "github.com/jump-dev/ParametricOptInterface.jl.git", push_preview = true, ) diff --git a/docs/src/Examples/example.md b/docs/src/Examples/example.md index 813a4ca0..7debb5e6 100644 --- a/docs/src/Examples/example.md +++ b/docs/src/Examples/example.md @@ -4,20 +4,18 @@ Let's write a step-by-step example of `POI` usage at the MOI level. -First, we declare a [`ParametricOptInterface.Optimizer`](@ref) on top of a `MOI` optimizer. In the example, we consider `HiGHS` as the underlying solver: +First, we declare a [`ParametricOptInterface.Optimizer`](@ref) on top of a `MOI` +optimizer. In the example, we consider `HiGHS` as the underlying solver: ```@example moi1 -using HiGHS -using MathOptInterface -using ParametricOptInterface - -const MOI = MathOptInterface -const POI = ParametricOptInterface - +import HiGHS +import MathOptInterface as MOI +import ParametricOptInterface as POI optimizer = POI.Optimizer(HiGHS.Optimizer()) ``` -We declare the variable `x` as in a typical `MOI` model, and we add a non-negativity constraint: +We declare the variable `x` as in a typical `MOI` model, and we add a +non-negativity constraint: ```@example moi1 x = MOI.add_variables(optimizer, 2) @@ -26,7 +24,9 @@ for x_i in x end ``` -Now, let's consider 3 `MOI.Parameter`. Two of them, `y`, `z`, will be placed in the constraints and one, `w`, in the objective function. We'll start all three of them with a value equal to `0`: +Now, let's consider 3 `MOI.Parameter`. Two of them, `y`, `z`, will be placed in +the constraints and one, `w`, in the objective function. We'll start all three +of them with a value equal to `0`: ```@example moi1 w, cw = MOI.add_constrained_variable(optimizer, MOI.Parameter(0.0)) @@ -34,7 +34,9 @@ y, cy = MOI.add_constrained_variable(optimizer, MOI.Parameter(0.0)) z, cz = MOI.add_constrained_variable(optimizer, MOI.Parameter(0.0)) ``` -Let's add the constraints. Notice that we treat parameters and variables in the same way when building the functions that will be placed in some set to create a constraint (`Function-in-Set`): +Let's add the constraints. Notice that we treat parameters and variables in the +same way when building the functions that will be placed in some set to create a +constraint (`Function-in-Set`): ```@example moi1 cons1 = MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([2.0, 1.0, 3.0], [x[1], x[2], y]), 0.0) @@ -59,7 +61,8 @@ MOI.get(optimizer, MOI.TerminationStatus()) MOI.get(optimizer, MOI.PrimalStatus()) ``` -Given the optimized solution, we check that its value is, as expected, equal to `28/3`, and the solution vector `x` is `[4/3, 4/3]`: +Given the optimized solution, we check that its value is, as expected, equal to +`28/3`, and the solution vector `x` is `[4/3, 4/3]`: ```@example moi1 isapprox(MOI.get(optimizer, MOI.ObjectiveValue()), 28/3, atol = 1e-4) @@ -67,7 +70,8 @@ isapprox(MOI.get(optimizer, MOI.VariablePrimal(), x[1]), 4/3, atol = 1e-4) isapprox(MOI.get(optimizer, MOI.VariablePrimal(), x[2]), 4/3, atol = 1e-4) ``` -We can also retrieve the dual values associated to each parameter, **as they are all additive**: +We can also retrieve the dual values associated to each parameter, +**as they are all additive**: ```@example moi1 MOI.get(optimizer, MOI.ConstraintDual(), cy) @@ -75,24 +79,40 @@ MOI.get(optimizer, MOI.ConstraintDual(), cz) MOI.get(optimizer, MOI.ConstraintDual(), cw) ``` -Notice the direct relationship in this case between the parameters' duals and the associated constraints' duals. -The `y` parameter, for example, only appears in the `cons1`. If we compare their duals, we can check that the dual of `y` is equal to its coefficient in `cons1` multiplied by the constraint's dual itself, as expected: +Notice the direct relationship in this case between the parameters' duals and +the associated constraints' duals. + +The `y` parameter, for example, only appears in the `cons1`. If we compare +their duals, we can check that the dual of `y` is equal to its coefficient in +`cons1` multiplied by the constraint's dual itself, as expected: ```@example moi1 -isapprox(MOI.get(optimizer, MOI.ConstraintDual(), cy), 3*MOI.get(optimizer, MOI.ConstraintDual(), ci1), atol = 1e-4) +isapprox( + MOI.get(optimizer, MOI.ConstraintDual(), cy), + 3*MOI.get(optimizer, MOI.ConstraintDual(), ci1); + atol = 1e-4, +) ``` -The same is valid for the remaining parameters. In case a parameter appears in more than one constraint, or both some constraints and in the objective function, its dual will be equal to the linear combination of the functions' duals multiplied by the respective coefficients. +The same is valid for the remaining parameters. In case a parameter appears in +more than one constraint, or both some constraints and in the objective +function, its dual will be equal to the linear combination of the functions' +duals multiplied by the respective coefficients. + +So far, we only added some parameters that had no influence at first in solving +the model. Let's change the values associated to each parameter to assess its +implications. -So far, we only added some parameters that had no influence at first in solving the model. Let's change the values associated to each parameter to assess its implications. -First, we set the value of parameters `y` and `z` to `1.0`. Notice that we are changing the feasible set of the decision variables: +First, we set the value of parameters `y` and `z` to `1.0`. Notice that we are +changing the feasible set of the decision variables: ```@example moi1 MOI.set(optimizer, POI.ParameterValue(), y, 1.0) MOI.set(optimizer, POI.ParameterValue(), z, 1.0) ``` -However, if we check the optimized model now, there will be no changes in the objective function value or the in the optimized decision variables: +However, if we check the optimized model now, there will be no changes in the +objective function value or the in the optimized decision variables: ```@example moi1 isapprox.(MOI.get(optimizer, MOI.ObjectiveValue()), 28/3, atol = 1e-4) @@ -100,20 +120,28 @@ isapprox.(MOI.get(optimizer, MOI.VariablePrimal(), x[1]), 4/3, atol = 1e-4) isapprox.(MOI.get(optimizer, MOI.VariablePrimal(), x[2]), 4/3, atol = 1e-4) ``` -Although we changed the parameter values, we didn't optimize the model yet. Thus, **to apply the parameters' changes, the model must be optimized again**: +Although we changed the parameter values, we didn't optimize the model yet. +Thus, **to apply the parameters' changes, the model must be optimized again**: ```@example moi1 MOI.optimize!(optimizer) ``` -The `MOI.optimize!()` function handles the necessary updates, properly fowarding the new outer model (`POI` model) additions to the inner model (`MOI` model) which will be handled by the solver. Now we can assess the updated optimized information: +The `MOI.optimize!()` function handles the necessary updates, properly fowarding +the new outer model (`POI` model) additions to the inner model (`MOI` model) +which will be handled by the solver. Now we can assess the updated optimized +information: ```@example moi1 isapprox.(MOI.get(optimizer, MOI.ObjectiveValue()), 3.0, atol = 1e-4) MOI.get.(optimizer, MOI.VariablePrimal(), x) == [0.0, 1.0] ``` -If we update the parameter `w`, associated to the objective function, we are simply adding a constant to it. Notice how the new objective function is precisely equal to the previous one plus the new value of `w`. In addition, as we didn't update the feasible set, the optimized decision variables remain the same. +If we update the parameter `w`, associated to the objective function, we are +simply adding a constant to it. Notice how the new objective function is +precisely equal to the previous one plus the new value of `w`. In addition, as +we didn't update the feasible set, the optimized decision variables remain the +same. ```@example moi1 MOI.set(optimizer, POI.ParameterValue(), w, 2.0) @@ -128,7 +156,8 @@ MOI.get.(optimizer, MOI.VariablePrimal(), x) == [0.0, 1.0] Let's write a step-by-step example of `POI` usage at the JuMP level. -First, we declare a `Model` on top of a `Optimizer` of an underlying solver. In the example, we consider `HiGHS` as the underlying solver: +First, we declare a `Model` on top of a `Optimizer` of an underlying solver. In +the example, we consider `HiGHS` as the underlying solver: ```@example jump1 using HiGHS @@ -146,7 +175,9 @@ We declare the variable `x` as in a typical `JuMP` model: @variable(model, x[i = 1:2] >= 0) ``` -Now, let's consider 3 `MOI.Parameter`. Two of them, `y`, `z`, will be placed in the constraints and one, `w`, in the objective function. We'll start all three of them with a value equal to `0`: +Now, let's consider 3 `MOI.Parameter`. Two of them, `y`, `z`, will be placed in +the constraints and one, `w`, in the objective function. We'll start all three +of them with a value equal to `0`: ```@example jump1 @variable(model, y in MOI.Parameter(0.0)) @@ -154,7 +185,8 @@ Now, let's consider 3 `MOI.Parameter`. Two of them, `y`, `z`, will be placed in @variable(model, w in MOI.Parameter(0.0)) ``` -Let's add the constraints. Notice that we treat parameters the same way we treat variables when writing the model: +Let's add the constraints. Notice that we treat parameters the same way we treat +variables when writing the model: ```@example jump1 @constraint(model, c1, 2x[1] + x[2] + 3y <= 4) @@ -175,7 +207,8 @@ termination_status(model) primal_status(model) ``` -Given the optimized solution, we check that its value is, as expected, equal to `28/3`, and the solution vector `x` is `[4/3, 4/3]`: +Given the optimized solution, we check that its value is, as expected, equal to +`28/3`, and the solution vector `x` is `[4/3, 4/3]`: ```@example jump1 isapprox(objective_value(model), 28/3) @@ -320,56 +353,36 @@ Users that just want everything to work can use the default value `POI.ONLY_CONS Let's start with a simple quadratic problem ```@example moi2 -using Ipopt -using MathOptInterface -using ParametricOptInterface - -const MOI = MathOptInterface -const POI = ParametricOptInterface - -optimizer = POI.Optimizer(Ipopt.Optimizer()) - -x = MOI.add_variable(optimizer) -y = MOI.add_variable(optimizer) -MOI.add_constraint(optimizer, x, MOI.GreaterThan(0.0)) -MOI.add_constraint(optimizer, y, MOI.GreaterThan(0.0)) - -cons1 = MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([2.0, 1.0], [x, y]), 0.0) -ci1 = MOI.add_constraint(optimizer, cons1, MOI.LessThan(4.0)) -cons2 = MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([1.0, 2.0], [x, y]), 0.0) -ci2 = MOI.add_constraint(optimizer, cons2, MOI.LessThan(4.0)) - -MOI.set(optimizer, MOI.ObjectiveSense(), MOI.MAX_SENSE) -obj_func = MOI.ScalarQuadraticFunction( - [MOI.ScalarQuadraticTerm(1.0, x, x) - MOI.ScalarQuadraticTerm(1.0, y, y)], - MOI.ScalarAffineTerm{Float64}[], - 0.0, -) -MOI.set( - optimizer, - MOI.ObjectiveFunction{MOI.ScalarQuadraticFunction{Float64}}(), - obj_func, -) +import Ipopt +import MathOptInterface as MOI +import ParametricOptInterface as POI +model = POI.Optimizer(Ipopt.Optimizer()) +x, _ = MOI.add_constrained_variable(model, MOI.GreaterThan(0.0)) +y, _ = MOI.add_constrained_variable(model, MOI.GreaterThan(0.0)) +ci1 = MOI.add_constraint(model, 2.0 * x + 1.0 * y, MOI.LessThan(4.0)) +ci2 = MOI.add_constraint(model, 1.0 * x + 2.0 * y, MOI.LessThan(4.0)) +MOI.set(model, MOI.ObjectiveSense(), MOI.MAX_SENSE) +obj_func = 1.0 * x * x + 1.0 * y * y +MOI.set(model, MOI.ObjectiveFunction{typeof(obj_func)}(), obj_func) ``` To multiply a parameter in a quadratic term, the user will need to use the `POI.QuadraticObjectiveCoef` model attribute. ```@example moi2 -p = first(MOI.add_constrained_variable.(optimizer, MOI.Parameter(1.0))) -MOI.set(optimizer, POI.QuadraticObjectiveCoef(), (x,y), p) +p, _ = MOI.add_constrained_variable.(model, MOI.Parameter(1.0)) +MOI.set(model, POI.QuadraticObjectiveCoef(), (x, y), p) ``` This function will add the term `p*xy` to the objective function. It's also possible to multiply a scalar affine function to the quadratic term. ```@example moi2 -MOI.set(optimizer, POI.QuadraticObjectiveCoef(), (x,y), 2p+3) +MOI.set(model, POI.QuadraticObjectiveCoef(), (x, y), 2 * p + 3) ``` -This will set the term `(2p+3)*xy` to the objective function (it overwrites the last set). -Then, just optimize the model. +This will set the term `(2p+3)*xy` to the objective function (it overwrites the +last set). Then, just optimize the model. ```@example moi2 MOI.optimize!(model) diff --git a/docs/src/Examples/markowitz.md b/docs/src/Examples/markowitz.md index 800fd595..6215c2a3 100644 --- a/docs/src/Examples/markowitz.md +++ b/docs/src/Examples/markowitz.md @@ -1,9 +1,12 @@ # Markowitz Efficient Frontier In this example, we solve the classical portfolio problem where we introduce the -weight parameter $\gamma$ and maximize $\gamma \text{ risk} - \text{expected return}$. By updating the values of $\gamma$ we trace the efficient frontier. +weight parameter $\gamma$ and maximize $\gamma \text{ risk} - \text{expected return}$. -Given the prices changes with mean $\mu$ and covariance $\Sigma$, we can construct the classical portfolio problem: +By updating the values of $\gamma$ we trace the efficient frontier. + +Given the prices changes with mean $\mu$ and covariance $\Sigma$, we can +construct the classical portfolio problem: $$\begin{array}{ll} \text{maximize} & \gamma* x^T \mu - x^T \Sigma x \\ @@ -13,56 +16,39 @@ $$\begin{array}{ll} The problem data was gotten from the example [portfolio optimization](https://jump.dev/Convex.jl/dev/examples/portfolio_optimization/portfolio_optimization2/) -```julia -using ParametricOptInterface, MathOptInterface, JuMP, Ipopt -using LinearAlgebra, Plots - -const POI = ParametricOptInterface -const MOI = MathOptInterface - -# generate problem data -μ = [11.5; 9.5; 6] / 100 #expected returns -Σ = [ - 166 34 58 #covariance matrix - 34 64 4 - 58 4 100 -] / 100^2 - +```@repl markowitz +using JuMP +import Ipopt +import ParametricOptInterface as POI +import Plots +μ = [11.5; 9.5; 6] / 100 +Σ = [166 34 58; 34 64 4; 58 4 100] / 100^2 ``` We first build the model with $\gamma$ as parameter in POI - -```julia -function first_model(μ,Σ) - cached = MOI.Bridges.full_bridge_optimizer( - MOIU.CachingOptimizer( - MOIU.UniversalFallback(MOIU.Model{Float64}()), - Ipopt.Optimizer(), - ), - Float64, - ) - optimizer = POI.Optimizer(cached) - portfolio = direct_model(optimizer) +```@repl markowitz +function first_model(μ, Σ) + portfolio = Model() do + inner = MOI.instantiate(Ipopt.Optimizer; with_cache_type = Float64) + return POI.Optimizer(inner) + end set_silent(portfolio) - N = length(μ) @variable(portfolio, x[1:N] >= 0) - @variable(portfolio, γ in MOI.Parameter(0.0)) - - @objective(portfolio, Max, γ*dot(μ,x) - x' * Σ * x) + @variable(portfolio, γ in Parameter(0.0)) + @objective(portfolio, Max, γ * μ' * x - x' * Σ * x) @constraint(portfolio, sum(x) == 1) optimize!(portfolio) - return portfolio end ``` Then, we update the $\gamma$ value in the model -```julia -function update_model!(portfolio,γ_value) +```@repl markowitz +function update_model!(portfolio, γ_value) γ = portfolio[:γ] - MOI.set(portfolio, POI.ParameterValue(), γ, γ_value) + set_parameter_value(γ, γ_value) optimize!(portfolio) return portfolio end @@ -70,38 +56,45 @@ end Collecting all the return and risk resuls for each $\gamma$ -```julia -function add_to_dict(portfolios_values,portfolio,μ,Σ) +```@repl markowitz +function add_to_dict(portfolios_values, portfolio, μ, Σ) γ = portfolio[:γ] γ_value = value(γ) x = portfolio[:x] x_value = value.(x) - portfolio_return = dot(μ,x_value) + portfolio_return = μ' * x_value portfolio_deviation = x_value' * Σ * x_value - portfolios_values[γ_value] = (portfolio_return,portfolio_deviation) + portfolios_values[γ_value] = (portfolio_return, portfolio_deviation) + return end ``` Run the portfolio optimization for different values of $\gamma$ -```julia -portfolio = first_model(μ,Σ) +```@repl markowitz +portfolio = first_model(μ, Σ) portfolios_values = Dict() # Create a reference to the model to change it later portfolio_ref = [portfolio] -add_to_dict(portfolios_values,portfolio,μ,Σ) - +add_to_dict(portfolios_values, portfolio, μ, Σ) for γ_value in 0.02:0.02:1.0 - portfolio_ref[] = update_model!(portfolio_ref[],γ_value) - add_to_dict(portfolios_values,portfolio_ref[],μ,Σ) + portfolio_ref[] = update_model!(portfolio_ref[], γ_value) + add_to_dict(portfolios_values,portfolio_ref[], μ, Σ) end ``` Plot the efficient frontier -```julia -portfolios_values = sort(portfolios_values,by=x->x[1]) -portfolios_values_matrix = hcat([[v[1],v[2]] for v in values(portfolios_values)]...)' -plot(portfolios_values_matrix[:,2],portfolios_values_matrix[:,1],legend=false, -xlabel="Standard Deviation", ylabel = "Return", title = "Efficient Frontier") -``` \ No newline at end of file +```@repl markowitz +sort!(portfolios_values, by = first) +portfolios_values_matrix = + hcat([[v[1], v[2]] for v in values(portfolios_values)]...)' +Plots.plot( + portfolios_values_matrix[:,2], + portfolios_values_matrix[:,1]; + legend = false, + xlabel = "Standard Deviation", + ylabel = "Return", + title = "Efficient Frontier", +) +``` diff --git a/docs/src/manual.md b/docs/src/manual.md index 41f8ce6f..8a00c73a 100644 --- a/docs/src/manual.md +++ b/docs/src/manual.md @@ -1,56 +1,76 @@ +```@meta +CurrentModule = ParametricOptInterface +``` + # Manual ## Why use parameters? -A typical optimization model built using `MathOptInterface.jl` (`MOI`for short) has two main components: +A typical optimization model built using `MathOptInterface.jl` (`MOI`for short) +has two main components: + 1. Variables 2. Constants -Using these basic elements, one can create functions and sets that, together, form the desired optimization model. The goal of `POI` is the implementation of a third type, parameters, which -* are declared similar to a variable, and inherits some functionalities (e.g. dual calculation) -* acts like a constant, in the sense that it has a fixed value that will remain the same unless explicitely changed by the user +Using these basic elements, one can create functions and sets that, together, +form the desired optimization model. The goal of `POI` is the implementation of +a third type, parameters, which: + +* are declared similar to a variable, and inherits some functionalities (for + example, dual calculation) +* acts like a constant, in the sense that it has a fixed value that will remain + the same unless explicitely changed by the user -A main concern is to efficiently implement this new type, as one typical usage is to change its value to analyze the model behavior, without the need to build a new one from scratch. +A main concern is to efficiently implement this new type, as one typical usage +is to change its value to analyze the model behavior, without the need to build +a new one from scratch. ## How it works -The main idea applied in POI is that the interaction between the solver, e.g. `HiGHS`, and the optimization model will be handled by `MOI` as usual. Because of that, `POI` is a higher level wrapper around `MOI`, responsible for receiving variables, constants and parameters, and forwarding to the lower level model only variables and constants. +The main idea applied in POI is that the interaction between the solver, for +example `HiGHS`, and the optimization model will be handled by `MOI` as usual. -As `POI` receives parameters, it must analyze and decide how they should be handled on the lower level optimization model (the `MOI` model). +Because of that, `POI` is a higher level wrapper around `MOI`, responsible for +receiving variables, constants and parameters, and forwarding to the lower level +model only variables and constants. + +As `POI` receives parameters, it must analyze and decide how they should be +handled on the lower level optimization model (the `MOI` model). ## Usage -In this manual we describe how to interact with the optimization model at the MOI level. In the [Examples](@ref) section you can find some tutorials with the JuMP usage. +In this manual we describe how to interact with the optimization model at the +MOI level. In the _Examples_ section you can find some tutorials with the +JuMP usage. ### Supported constraints -This is a list of supported `MOI` constraint functions that can handle parameters. If you try to add a parameter to -a function that is not listed here, it will return an unsupported error. +This is a list of supported `MOI` constraint functions that can handle +parameters. If you try to add a parameter to a function that is not listed here, +it will return an unsupported error. -| MOI Function | -|:-------| -| `ScalarAffineFunction` | -| `ScalarQuadraticFunction` | -| `VectorAffineFunction` | +| MOI Function | +| :------------------------ | +| `ScalarAffineFunction` | +| `ScalarQuadraticFunction` | +| `VectorAffineFunction` | ### Supported objective functions -| MOI Function | -|:-------| -| `ScalarAffineFunction` | -| `ScalarQuadraticFunction` | +| MOI Function | +| :------------------------ | +| `ScalarAffineFunction` | +| `ScalarQuadraticFunction` | ### Declare a Optimizer -In order to use parameters, the user needs to declare a [`ParametricOptInterface.Optimizer`](@ref) on top of a `MOI` optimizer, such as `HiGHS.Optimizer()`. +In order to use parameters, the user needs to declare an +[`Optimizer`](@ref) on top of a `MOI` optimizer, such as `HiGHS.Optimizer()`. -```julia -using ParametricOptInterface, MathOptInterface, HiGHS -# Rename ParametricOptInterface and MathOptInterface to simplify the code -const POI = ParametricOptInterface -const MOI = MathOptInterface -# Define a Optimizer on top of the MOI optimizer +```@repl manual +import ParametricOptInterface as POI +import HiGHS optimizer = POI.Optimizer(HiGHS.Optimizer()) ``` @@ -58,31 +78,37 @@ optimizer = POI.Optimizer(HiGHS.Optimizer()) A `MOI.Parameter` is a set used to define a variable with a fixed value that can be changed by the user. It is analogous to `MOI.EqualTo`, but can be used -by special methods like the ones in this package to remove the fixed variable from the -optimization problem. This permits the usage of multiplicative parameters in lienar models -and might speedup solves since the number of variables is reduced. +by special methods like the ones in this package to remove the fixed variable +from the optimization problem. This permits the usage of multiplicative +parameters in linear models and might speedup solves since the number of +variables is reduced. ### Adding a new parameter to a model -To add a parameter to a model, we must use the `MOI.add_constrained_variable()` function, passing as its arguments the model and a `MOI.Parameter` with its given value: +To add a parameter to a model, we must use the `MOI.add_constrained_variable` +function, passing as its arguments the model and a `MOI.Parameter` with its +given value: -```julia +```@repl manual y, cy = MOI.add_constrained_variable(optimizer, MOI.Parameter(0.0)) ``` ### Changing the parameter value -To change a given parameter's value, access its `VariableIndex` and set it to the new value using the `MOI.Parameter` structure. +To change a given parameter's value, access its `VariableIndex` and set it to +the new value using the `MOI.Parameter` structure. -```julia +```@repl manual MOI.set(optimizer, POI.ParameterValue(), y, MOI.Parameter(2.0)) ``` ### Retrieving the dual of a parameter -Given an optimized model, one can compute the dual associated to a parameter, **as long as it is an additive term in the constraints or objective**. -One can do so by getting the `MOI.ConstraintDual` attribute of the parameter's `MOI.ConstraintIndex`: +Given an optimized model, one can compute the dual associated to a parameter, +**as long as it is an additive term in the constraints or objective**. +One can do so by getting the `MOI.ConstraintDual` attribute of the parameter's +`MOI.ConstraintIndex`: ```julia -MOI.get(optimizer, POI.ParameterDual(), y) +julia> MOI.get(optimizer, POI.ParameterDual(), y) ``` diff --git a/docs/src/reference.md b/docs/src/reference.md index acb5eba3..42864d89 100644 --- a/docs/src/reference.md +++ b/docs/src/reference.md @@ -1,8 +1,33 @@ +```@meta +CurrentModule = ParametricOptInterface +``` + # Reference +This page lists the public API of ParametericOptInterface. + +Load the module with: +```julia +import ParametericOptInterface as POI +``` +and then prefix all calls with `POI.` to create `POI.`. + +## `Optimizer` +```@docs +Optimizer +``` + +## `ConstraintsInterpretation` +```@docs +ConstraintsInterpretation +``` + +## `ParameterDual` +```@docs +ParameterDual +``` + +## `ParameterValue` ```@docs -ParametricOptInterface.ConstraintsInterpretation -ParametricOptInterface.Optimizer -ParametricOptInterface.ParameterDual -ParametricOptInterface.ParameterValue -``` \ No newline at end of file +ParameterValue +``` diff --git a/src/MOI_wrapper.jl b/src/MOI_wrapper.jl index 6ef52d36..70b52a3d 100644 --- a/src/MOI_wrapper.jl +++ b/src/MOI_wrapper.jl @@ -1906,11 +1906,11 @@ end """ ConstraintsInterpretation <: MOI.AbstractOptimizerAttribute -Attribute to define how [`POI.Optimizer`](@ref) should interpret constraints. +Attribute to define how [`Optimizer`](@ref) should interpret constraints. - `POI.ONLY_CONSTRAINTS`: Only interpret `ScalarAffineFunction` constraints as linear constraints If an expression such as `x >= p1 + p2` appears it will be trated like a new constraint. - **This is the default behaviour of [`POI.Optimizer`](@ref)** + **This is the default behaviour of [`Optimizer`](@ref)** - `POI.ONLY_BOUNDS`: Only interpret `ScalarAffineFunction` constraints as a variable bound. This is valid for constraints such as `x >= p` or `x >= p1 + p2`. If a constraint `x1 + x2 >= p` appears, diff --git a/src/ParametricOptInterface.jl b/src/ParametricOptInterface.jl index 5c2080ad..8ebe027f 100644 --- a/src/ParametricOptInterface.jl +++ b/src/ParametricOptInterface.jl @@ -92,7 +92,7 @@ optimization model. to increase performance when the duals of parameters are not necessary. Defaults to `true`. - `save_original_objective_and_constraints`: If `true` saves the orginal function and set of the constraints - as well as the original objective function inside [`POI.Optimizer`](@ref). This is useful for printing the model + as well as the original objective function inside [`Optimizer`](@ref). This is useful for printing the model but greatly increases the memory footprint. Users might want to set it to `false` to increase performance in applications where you don't need to query the original expressions provided to the model in constraints or in the objective. Note that this might break printing or queries such as `MOI.get(model, MOI.ConstraintFunction(), c)`.