{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "---\n", "title: Problem Modification\n", "---" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Originally Contributed by**: Arpit Bhatia" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This tutorial deals with how to modify models after they have been created and solved.\n", "This functionality can be useful, for example, \n", "when we are solving many similar models in succession or generating the model dynamically. \n", "Additionally it is sometimes desirable for the solver to re-start from the last solution to \n", "reduce running times for successive solves (“hot-start”)." ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "using JuMP" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Modifying Variables" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "model = Model()\n", "@variable(model, x);" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Variable Bounds" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The `set_lower_bound` and `set_upper_bound` functions can be used to create as well as \n", "modify an existing variable bound." ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "3.0" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "set_lower_bound(x, 3)\n", "lower_bound(x)" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "2.0" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "set_lower_bound(x, 2)\n", "lower_bound(x)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can delete variable bounds using the `delete_lower_bound` and `delete_upper_bound` functions." ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "false" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "delete_lower_bound(x)\n", "has_lower_bound(x)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can assign a fixed value to a variable using `fix`." ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "5.0" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "fix(x, 5)\n", "fix_value(x)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "However, fixing a variable with existing bounds will throw an error." ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [], "source": [ "@variable(model, y >= 0);" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "ename": "LoadError", "evalue": "Unable to fix y to 2 because it has existing variable bounds. Consider calling `JuMP.fix(variable, value; force=true)` which will delete existing bounds before fixing the variable.", "output_type": "error", "traceback": [ "Unable to fix y to 2 because it has existing variable bounds. Consider calling `JuMP.fix(variable, value; force=true)` which will delete existing bounds before fixing the variable.", "", "Stacktrace:", " [1] error(::String) at ./error.jl:33", " [2] _moi_fix(::MathOptInterface.Utilities.CachingOptimizer{MathOptInterface.AbstractOptimizer,MathOptInterface.Utilities.UniversalFallback{MathOptInterface.Utilities.Model{Float64}}}, ::VariableRef, ::Int64, ::Bool) at /home/mbesancon/.julia/packages/JuMP/e0Uc2/src/variables.jl:553", " [3] fix(::VariableRef, ::Int64; force::Bool) at /home/mbesancon/.julia/packages/JuMP/e0Uc2/src/variables.jl:541", " [4] fix(::VariableRef, ::Int64) at /home/mbesancon/.julia/packages/JuMP/e0Uc2/src/variables.jl:541", " [5] top-level scope at In[8]:1", " [6] include_string(::Function, ::Module, ::String, ::String) at ./loading.jl:1091", " [7] execute_code(::String, ::String) at /home/mbesancon/.julia/packages/IJulia/a1SNk/src/execute_request.jl:27", " [8] execute_request(::ZMQ.Socket, ::IJulia.Msg) at /home/mbesancon/.julia/packages/IJulia/a1SNk/src/execute_request.jl:86", " [9] #invokelatest#1 at ./essentials.jl:710 [inlined]", " [10] invokelatest at ./essentials.jl:709 [inlined]", " [11] eventloop(::ZMQ.Socket) at /home/mbesancon/.julia/packages/IJulia/a1SNk/src/eventloop.jl:8", " [12] (::IJulia.var\"#15#18\")() at ./task.jl:356" ] } ], "source": [ "fix(y, 2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "As we can see in the error message above, \n", "we have to specify to JuMP that we wish to forcefuly remove the bound." ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "2.0" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "fix(y, 2; force = true)\n", "fix_value(y)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can also call the `unfix` function to remove the fixed value." ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "false" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "unfix(x)\n", "is_fixed(x)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Deleting Variables" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The `all_variables` function returns a list of all variables present in the model." ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "2-element Array{VariableRef,1}:\n", " x\n", " y" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "all_variables(model)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To delete variables from a model, we can use the `delete` function." ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "1-element Array{VariableRef,1}:\n", " y" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "delete(model, x)\n", "all_variables(model)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can also check whether a variable is a valid JuMP variable in a model using the `is_valid` function." ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "false" ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ "is_valid(model, x)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Modifying Constraints" ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [], "source": [ "model = Model()\n", "@variable(model, x);" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Modifying a Variable Coefficient\n", "It is also possible to modify the scalar coefficients \n", "(but notably not yet the quadratic coefficients) using the `set_normalized_coefficient` function." ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [], "source": [ "@constraint(model, con, 2x <= 1);" ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [ { "data": { "text/latex": [ "con : $ 3 x \\leq 1.0 $" ], "text/plain": [ "con : 3 x ≤ 1.0" ] }, "execution_count": 16, "metadata": {}, "output_type": "execute_result" } ], "source": [ "set_normalized_coefficient(con, x, 3)\n", "con" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Deleting a Constraint\n", "Just like for deleting variables, we can use the `delete` function for constraints as well." ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "false" ] }, "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ "delete(model, con)\n", "is_valid(model, con)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Modifying the Objective" ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [], "source": [ "model = Model()\n", "@variable(model, x)\n", "@objective(model, Min, 7x + 4);" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The function `objective_function` is used to query the objective of a model." ] }, { "cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [ { "data": { "text/latex": [ "$$ 7 x + 4 $$" ], "text/plain": [ "7 x + 4" ] }, "execution_count": 19, "metadata": {}, "output_type": "execute_result" } ], "source": [ "objective_function(model)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "`objective_sense` is similarily used to query the objective sense of a model." ] }, { "cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "MIN_SENSE::OptimizationSense = 0" ] }, "execution_count": 20, "metadata": {}, "output_type": "execute_result" } ], "source": [ "objective_sense(model)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To easiest way to change the objective is to simply call `@objective` again \n", "- the previous objective function and sense will be replaced." ] }, { "cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [ { "data": { "text/latex": [ "$$ 8 x + 3 $$" ], "text/plain": [ "8 x + 3" ] }, "execution_count": 21, "metadata": {}, "output_type": "execute_result" } ], "source": [ "@objective(model, Max, 8x + 3)\n", "objective_function(model)" ] }, { "cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "MAX_SENSE::OptimizationSense = 1" ] }, "execution_count": 22, "metadata": {}, "output_type": "execute_result" } ], "source": [ "objective_sense(model)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Another way is to change the objective is to \n", "use the low-level functions `set_objective_function` and `set_objective_sense`." ] }, { "cell_type": "code", "execution_count": 23, "metadata": {}, "outputs": [ { "data": { "text/latex": [ "$$ 5 x + 11 $$" ], "text/plain": [ "5 x + 11" ] }, "execution_count": 23, "metadata": {}, "output_type": "execute_result" } ], "source": [ "set_objective_function(model, 5x + 11)\n", "objective_function(model)" ] }, { "cell_type": "code", "execution_count": 24, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "MIN_SENSE::OptimizationSense = 0" ] }, "execution_count": 24, "metadata": {}, "output_type": "execute_result" } ], "source": [ "set_objective_sense(model, MOI.MIN_SENSE) \n", "objective_sense(model)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Note that we can't use the Min and Max shortcuts here as `set_objective_sense` is a low level function." ] } ], "metadata": { "kernelspec": { "display_name": "Julia 1.5.1", "language": "julia", "name": "julia-1.5" }, "language_info": { "file_extension": ".jl", "mimetype": "application/julia", "name": "julia", "version": "1.5.1" } }, "nbformat": 4, "nbformat_minor": 2 }