Skip to article frontmatterSkip to article content
Contents
and

36. Linear Programming

In this lecture, we will need the following library. Install ortools using pip.

!pip install ortools
Output
Collecting ortools
  Using cached ortools-9.12.4544-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl.metadata (3.3 kB)
Collecting absl-py>=2.0.0 (from ortools)
  Using cached absl_py-2.1.0-py3-none-any.whl.metadata (2.3 kB)
Requirement already satisfied: numpy>=1.13.3 in /opt/hostedtoolcache/Python/3.12.9/x64/lib/python3.12/site-packages (from ortools) (2.1.3)
Requirement already satisfied: pandas>=2.0.0 in /opt/hostedtoolcache/Python/3.12.9/x64/lib/python3.12/site-packages (from ortools) (2.2.3)
Collecting protobuf<5.30,>=5.29.3 (from ortools)
  Using cached protobuf-5.29.3-cp38-abi3-manylinux2014_x86_64.whl.metadata (592 bytes)
Collecting immutabledict>=3.0.0 (from ortools)
  Using cached immutabledict-4.2.1-py3-none-any.whl.metadata (3.5 kB)
Requirement already satisfied: python-dateutil>=2.8.2 in /opt/hostedtoolcache/Python/3.12.9/x64/lib/python3.12/site-packages (from pandas>=2.0.0->ortools) (2.9.0.post0)
Requirement already satisfied: pytz>=2020.1 in /opt/hostedtoolcache/Python/3.12.9/x64/lib/python3.12/site-packages (from pandas>=2.0.0->ortools) (2025.1)
Requirement already satisfied: tzdata>=2022.7 in /opt/hostedtoolcache/Python/3.12.9/x64/lib/python3.12/site-packages (from pandas>=2.0.0->ortools) (2025.1)

Requirement already satisfied: six>=1.5 in /opt/hostedtoolcache/Python/3.12.9/x64/lib/python3.12/site-packages (from python-dateutil>=2.8.2->pandas>=2.0.0->ortools) (1.17.0)
Using cached ortools-9.12.4544-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl (25.0 MB)
Using cached absl_py-2.1.0-py3-none-any.whl (133 kB)
Using cached immutabledict-4.2.1-py3-none-any.whl (4.7 kB)
Using cached protobuf-5.29.3-cp38-abi3-manylinux2014_x86_64.whl (319 kB)
Installing collected packages: protobuf, immutabledict, absl-py, ortools
Successfully installed absl-py-2.1.0 immutabledict-4.2.1 ortools-9.12.4544 protobuf-5.29.3

36.1Overview

Linear programming problems either maximize or minimize a linear objective function subject to a set of linear equality and/or inequality constraints.

Linear programs come in pairs:

  • an original primal problem, and

  • an associated dual problem.

If a primal problem involves maximization, the dual problem involves minimization.

If a primal problem involves minimization*, the dual problem involves *maximization.

We provide a standard form of a linear program and methods to transform other forms of linear programming problems into a standard form.

We tell how to solve a linear programming problem using SciPy and Google OR-Tools.

Let’s start with some standard imports.

import numpy as np
from ortools.linear_solver import pywraplp
from scipy.optimize import linprog
import matplotlib.pyplot as plt
from matplotlib.patches import Polygon

Let’s start with some examples of linear programming problem.

36.2Example 1: production problem

This example was created by Bertsimas (1997)

Suppose that a factory can produce two goods called Product 1 and Product 2.

To produce each product requires both material and labor.

Selling each product generates revenue.

Required per unit material and labor inputs and revenues are shown in table below:

Product 1Product 2
Material25
Labor42
Revenue34

30 units of material and 20 units of labor available.

A firm’s problem is to construct a production plan that uses its 30 units of materials and 20 units of labor to maximize its revenue.

Let xix_i denote the quantity of Product ii that the firm produces and zz denote the total revenue.

This problem can be formulated as:

maxx1,x2 z=3x1+4x2subject to  2x1+5x2304x1+2x220x1,x20\begin{aligned} \max_{x_1,x_2} \ & z = 3 x_1 + 4 x_2 \\ \mbox{subject to } \ & 2 x_1 + 5 x_2 \le 30 \\ & 4 x_1 + 2 x_2 \le 20 \\ & x_1, x_2 \ge 0 \\ \end{aligned}

The following graph illustrates the firm’s constraints and iso-revenue lines.

Iso-revenue lines show all the combinations of materials and labor that produce the same revenue.

Source
fig, ax = plt.subplots()
# Draw constraint lines
ax.set_xlim(0,15)
ax.set_ylim(0,10)
x1 = np.linspace(0, 15)
ax.plot(x1, 6-0.4*x1, label="$2x_1 + 5x_2=30$")
ax.plot(x1, 10-2*x1, label="$4x_1 + 2x_2=20$")


# Draw the feasible region
feasible_set = Polygon(np.array([[0, 0],[0, 6],[2.5, 5],[5, 0]]), alpha=0.1)
ax.add_patch(feasible_set)

# Draw the objective function
ax.plot(x1, 3.875-0.75*x1, label="iso-revenue lines",color='k',linewidth=0.75)
ax.plot(x1, 5.375-0.75*x1, color='k',linewidth=0.75)
ax.plot(x1, 6.875-0.75*x1, color='k',linewidth=0.75)

# Draw the optimal solution
ax.plot(2.5, 5, ".", label="optimal solution")
ax.set_xlabel("$x_1$")
ax.set_ylabel("$x_2$")
ax.legend()

plt.show()
<Figure size 640x480 with 1 Axes>

The blue region is the feasible set within which all constraints are satisfied.

Parallel black lines are iso-revenue lines.

The firm’s objective is to find the parallel black lines to the upper boundary of the feasible set.

The intersection of the feasible set and the highest black line delineates the optimal set.

In this example, the optimal set is the point (2.5,5)(2.5, 5).

36.2.1Computation: using OR-Tools

Let’s try to solve the same problem using the package ortools.linear_solver.

The following cell instantiates a solver and creates two variables specifying the range of values that they can have.

# Instantiate a GLOP(Google Linear Optimization Package) solver
solver = pywraplp.Solver.CreateSolver('GLOP')

Let’s create two variables x1x_1 and x2x_2 such that they can only have nonnegative values.

# Create the two variables and let them take on any non-negative value.
x1 = solver.NumVar(0, solver.infinity(), 'x1')
x2 = solver.NumVar(0, solver.infinity(), 'x2')

Add the constraints to the problem.

# Constraint 1: 2x_1 + 5x_2 <= 30.0
solver.Add(2 * x1 + 5 * x2 <= 30.0)

# Constraint 2: 4x_1 + 2x_2 <= 20.0
solver.Add(4 * x1 + 2 * x2 <= 20.0)
<ortools.linear_solver.pywraplp.Constraint; proxy of <Swig Object of type 'operations_research::MPConstraint *' at 0x7fb58c1fb270> >

Let’s specify the objective function. We use solver.Maximize method in the case when we want to maximize the objective function and in the case of minimization we can use solver.Minimize.

# Objective function: 3x_1 + 4x_2
solver.Maximize(3 * x1 + 4 * x2)

Once we solve the problem, we can check whether the solver was successful in solving the problem using its status. If it’s successful, then the status will be equal to pywraplp.Solver.OPTIMAL.

# Solve the system.
status = solver.Solve()

if status == pywraplp.Solver.OPTIMAL:
    print('Objective value =', solver.Objective().Value())
    print(f'(x1, x2): ({x1.solution_value():.2}, {x2.solution_value():.2})')
else:
    print('The problem does not have an optimal solution.')
Objective value = 27.5
(x1, x2): (2.5, 5.0)

36.3Example 2: investment problem

We now consider a problem posed and solved by Hu (2018).

A mutual fund has $100,000 \$ 100,000 to be invested over a three-year horizon.

Three investment options are available:

  1. Annuity: the fund can pay a same amount of new capital at the beginning of each of three years and receive a payoff of 130% of total capital invested at the end of the third year. Once the mutual fund decides to invest in this annuity, it has to keep investing in all subsequent years in the three year horizon.

  2. Bank account: the fund can deposit any amount into a bank at the beginning of each year and receive its capital plus 6% interest at the end of that year. In addition, the mutual fund is permitted to borrow no more than $20,000 at the beginning of each year and is asked to pay back the amount borrowed plus 6% interest at the end of the year. The mutual fund can choose whether to deposit or borrow at the beginning of each year.

  3. Corporate bond: At the beginning of the second year, a corporate bond becomes available. The fund can buy an amount that is no more than $ \$ 50,000 of this bond at the beginning of the second year and at the end of the third year receive a payout of 130% of the amount invested in the bond.

The mutual fund’s objective is to maximize total payout that it owns at the end of the third year.

We can formulate this as a linear programming problem.

Let x1x_1 be the amount of put in the annuity, x2,x3,x4x_2, x_3, x_4 be bank deposit balances at the beginning of the three years, and x5x_5 be the amount invested in the corporate bond.

When x2,x3,x4x_2, x_3, x_4 are negative, it means that the mutual fund has borrowed from bank.

The table below shows the mutual fund’s decision variables together with the timing protocol described above:

Year 1Year 2Year 3
Annuityx1x_1x1x_1x1x_1
Bank accountx2x_2x3x_3x4x_4
Corporate bond0x5x_50

The mutual fund’s decision making proceeds according to the following timing protocol:

  1. At the beginning of the first year, the mutual fund decides how much to invest in the annuity and how much to deposit in the bank. This decision is subject to the constraint:

    x1+x2=100,000x_1 + x_2 = 100,000
  2. At the beginning of the second year, the mutual fund has a bank balance of 1.06x21.06 x_2. It must keep x1x_1 in the annuity. It can choose to put x5x_5 into the corporate bond, and put x3x_3 in the bank. These decisions are restricted by

    x1+x5=1.06x2x3x_1 + x_5 = 1.06 x_2 - x_3
  3. At the beginning of the third year, the mutual fund has a bank account balance equal to 1.06x31.06 x_3. It must again invest x1x_1 in the annuity, leaving it with a bank account balance equal to x4x_4. This situation is summarized by the restriction:

    x1=1.06x3x4x_1 = 1.06 x_3 - x_4

The mutual fund’s objective function, i.e., its wealth at the end of the third year is:

1.303x1+1.06x4+1.30x51.30 \cdot 3x_1 + 1.06 x_4 + 1.30 x_5

Thus, the mutual fund confronts the linear program:

maxx 1.303x1+1.06x4+1.30x5subject to  x1+x2=100,000x11.06x2+x3+x5=0x11.06x3+x4=0x220,000x320,000x420,000x550,000xj0,j=1,5xj unrestricted,j=2,3,4\begin{aligned} \max_{x} \ & 1.30 \cdot 3x_1 + 1.06 x_4 + 1.30 x_5 \\ \mbox{subject to } \ & x_1 + x_2 = 100,000\\ & x_1 - 1.06 x_2 + x_3 + x_5 = 0\\ & x_1 - 1.06 x_3 + x_4 = 0\\ & x_2 \ge -20,000\\ & x_3 \ge -20,000\\ & x_4 \ge -20,000\\ & x_5 \le 50,000\\ & x_j \ge 0, \quad j = 1,5\\ & x_j \ \text{unrestricted}, \quad j = 2,3,4\\ \end{aligned}

36.3.1Computation: using OR-Tools

Let’s try to solve the above problem using the package ortools.linear_solver.

The following cell instantiates a solver and creates two variables specifying the range of values that they can have.

# Instantiate a GLOP(Google Linear Optimization Package) solver
solver = pywraplp.Solver.CreateSolver('GLOP')

Let’s create five variables x1,x2,x3,x4,x_1, x_2, x_3, x_4, and x5x_5 such that they can only have the values defined in the above constraints.

# Create the variables using the ranges available from constraints
x1 = solver.NumVar(0, solver.infinity(), 'x1')
x2 = solver.NumVar(-20_000, solver.infinity(), 'x2')
x3 = solver.NumVar(-20_000, solver.infinity(), 'x3')
x4 = solver.NumVar(-20_000, solver.infinity(), 'x4')
x5 = solver.NumVar(0, 50_000, 'x5')

Add the constraints to the problem.

# Constraint 1: x_1 + x_2 = 100,000
solver.Add(x1 + x2 == 100_000.0)

# Constraint 2: x_1 - 1.06 * x_2 + x_3 + x_5 = 0
solver.Add(x1 - 1.06 * x2 + x3 + x5 == 0.0)

# Constraint 3: x_1 - 1.06 * x_3 + x_4 = 0
solver.Add(x1 - 1.06 * x3 + x4 == 0.0)
<ortools.linear_solver.pywraplp.Constraint; proxy of <Swig Object of type 'operations_research::MPConstraint *' at 0x7fb58b7af5d0> >

Let’s specify the objective function.

# Objective function: 1.30 * 3 * x_1 + 1.06 * x_4 + 1.30 * x_5
solver.Maximize(1.30 * 3 * x1 + 1.06 * x4 + 1.30 * x5)

Let’s solve the problem and check the status using pywraplp.Solver.OPTIMAL.

# Solve the system.
status = solver.Solve()

if status == pywraplp.Solver.OPTIMAL:
    print('Objective value =', solver.Objective().Value())
    x1_sol = round(x1.solution_value(), 3)
    x2_sol = round(x2.solution_value(), 3)
    x3_sol = round(x1.solution_value(), 3)
    x4_sol = round(x2.solution_value(), 3)
    x5_sol = round(x1.solution_value(), 3)
    print(f'(x1, x2, x3, x4, x5): ({x1_sol}, {x2_sol}, {x3_sol}, {x4_sol}, {x5_sol})')
else:
    print('The problem does not have an optimal solution.')
Objective value = 141018.24349792692
(x1, x2, x3, x4, x5): (24927.755, 75072.245, 24927.755, 75072.245, 24927.755)

OR-Tools tells us that the best investment strategy is:

  1. At the beginning of the first year, the mutual fund should buy $24,927.755 \$24,927.755 of the annuity. Its bank account balance should be $75,072.245 \$75,072.245.

  2. At the beginning of the second year, the mutual fund should buy $24,927.755 \$24,927.755 of the corporate bond and keep invest in the annuity. Its bank balance should be $24,927.755 \$24,927.755.

  3. At the beginning of the third year, the bank balance should be $75,072.245 \$75,072.245 .

  4. At the end of the third year, the mutual fund will get payouts from the annuity and corporate bond and repay its loan from the bank. At the end it will own $141,018.24 \$141,018.24 , so that it’s total net rate of return over the three periods is 41.02% 41.02\%.

36.4Standard form

For purposes of

  • unifying linear programs that are initially stated in superficially different forms, and

  • having a form that is convenient to put into black-box software packages,

it is useful to devote some effort to describe a standard form.

Our standard form is:

minx c1x1+c2x2++cnxnsubject to  a11x1+a12x2++a1nxn=b1a21x1+a22x2++a2nxn=b2am1x1+am2x2++amnxn=bmx1,x2,,xn0\begin{aligned} \min_{x} \ & c_1 x_1 + c_2 x_2 + \dots + c_n x_n \\ \mbox{subject to } \ & a_{11} x_1 + a_{12} x_2 + \dots + a_{1n} x_n = b_1 \\ & a_{21} x_1 + a_{22} x_2 + \dots + a_{2n} x_n = b_2 \\ & \quad \vdots \\ & a_{m1} x_1 + a_{m2} x_2 + \dots + a_{mn} x_n = b_m \\ & x_1, x_2, \dots, x_n \ge 0 \\ \end{aligned}

Let

A=[a11a12a1na21a22a2nam1am2amn],b=[b1b2bm],c=[c1c2cn],x=[x1x2xn].A = \begin{bmatrix} a_{11} & a_{12} & \dots & a_{1n} \\ a_{21} & a_{22} & \dots & a_{2n} \\ & & \vdots & \\ a_{m1} & a_{m2} & \dots & a_{mn} \\ \end{bmatrix}, \quad b = \begin{bmatrix} b_1 \\ b_2 \\ \vdots \\ b_m \\ \end{bmatrix}, \quad c = \begin{bmatrix} c_1 \\ c_2 \\ \vdots \\ c_n \\ \end{bmatrix}, \quad x = \begin{bmatrix} x_1 \\ x_2 \\ \vdots \\ x_n \\ \end{bmatrix}. \quad

The standard form linear programming problem can be expressed concisely as:

minx cxsubject to  Ax=bx0\begin{aligned} \min_{x} \ & c'x \\ \mbox{subject to } \ & Ax = b\\ & x \geq 0\\ \end{aligned}

Here, Ax=bAx = b means that the ii-th entry of AxAx equals the ii-th entry of bb for every ii.

Similarly, x0x \geq 0 means that xjx_j is greater than equal to 0 for every jj.

36.4.1Useful transformations

It is useful to know how to transform a problem that initially is not stated in the standard form into one that is.

By deploying the following steps, any linear programming problem can be transformed into an equivalent standard form linear programming problem.

  1. Objective function: If a problem is originally a constrained maximization problem, we can construct a new objective function that is the additive inverse of the original objective function. The transformed problem is then a minimization problem.

  2. Decision variables: Given a variable xjx_j satisfying xj0x_j \le 0, we can introduce a new variable xj=xjx_j' = - x_j and substitute it into original problem. Given a free variable xix_i with no restriction on its sign, we can introduce two new variables xj+x_j^+ and xjx_j^- satisfying xj+,xj0x_j^+, x_j^- \ge 0 and replace xjx_j by xj+xjx_j^+ - x_j^-.

  3. Inequality constraints: Given an inequality constraint j=1naijxj0\sum_{j=1}^n a_{ij}x_j \le 0, we can introduce a new variable sis_i, called a slack variable that satisfies si0s_i \ge 0 and replace the original constraint by j=1naijxj+si=0\sum_{j=1}^n a_{ij}x_j + s_i = 0.

Let’s apply the above steps to the two examples described above.

36.4.2Example 1: production problem

The original problem is:

maxx1,x2 3x1+4x2subject to  2x1+5x2304x1+2x220x1,x20\begin{aligned} \max_{x_1,x_2} \ & 3 x_1 + 4 x_2 \\ \mbox{subject to } \ & 2 x_1 + 5 x_2 \le 30 \\ & 4 x_1 + 2 x_2 \le 20 \\ & x_1, x_2 \ge 0 \\ \end{aligned}

This problem is equivalent to the following problem with a standard form:

minx1,x2 (3x1+4x2)subject to  2x1+5x2+s1=304x1+2x2+s2=20x1,x2,s1,s20\begin{aligned} \min_{x_1,x_2} \ & -(3 x_1 + 4 x_2) \\ \mbox{subject to } \ & 2 x_1 + 5 x_2 + s_1 = 30 \\ & 4 x_1 + 2 x_2 + s_2 = 20 \\ & x_1, x_2, s_1, s_2 \ge 0 \\ \end{aligned}

36.4.3Computation: using SciPy

The package scipy.optimize provides a function linprog to solve linear programming problems with a form below:

minx cxsubject to  AubxbubAeqx=beqlxu\begin{aligned} \min_{x} \ & c' x \\ \mbox{subject to } \ & A_{ub}x \le b_{ub} \\ & A_{eq}x = b_{eq} \\ & l \le x \le u \\ \end{aligned}

Aeq,beqA_{eq}, b_{eq} denote the equality constraint matrix and vector, and Aub,bubA_{ub}, b_{ub} denote the inequality constraint matrix and vector.

Let’s now try to solve the Problem 1 using SciPy.

# Construct parameters
c_ex1 = np.array([3, 4])

# Inequality constraints
A_ex1 = np.array([[2, 5],
                  [4, 2]])
b_ex1 = np.array([30,20])

Once we solve the problem, we can check whether the solver was successful in solving the problem using the boolean attribute success. If it’s successful, then the success attribute is set to True.

# Solve the problem
# we put a negative sign on the objective as linprog does minimization
res_ex1 = linprog(-c_ex1, A_ub=A_ex1, b_ub=b_ex1)

if res_ex1.success:
    # We use negative sign to get the optimal value (maximized value)
    print('Optimal Value:', -res_ex1.fun)
    print(f'(x1, x2): {res_ex1.x[0], res_ex1.x[1]}')
else:
    print('The problem does not have an optimal solution.')
Optimal Value: 27.5
(x1, x2): (np.float64(2.5), np.float64(5.0))

The optimal plan tells the factory to produce 2.5 units of Product 1 and 5 units of Product 2; that generates a maximizing value of revenue of 27.5.

We are using the linprog function as a black box.

Inside it, Python first transforms the problem into standard form.

To do that, for each inequality constraint it generates one slack variable.

Here the vector of slack variables is a two-dimensional NumPy array that equals bubAubxb_{ub} - A_{ub}x.

See the official documentation for more details.

36.4.4Example 2: investment problem

The original problem is:

maxx 1.303x1+1.06x4+1.30x5subject to  x1+x2=100,000x11.06x2+x3+x5=0x11.06x3+x4=0x220,000x320,000x420,000x550,000xj0,j=1,5xj unrestricted,j=2,3,4\begin{aligned} \max_{x} \ & 1.30 \cdot 3x_1 + 1.06 x_4 + 1.30 x_5 \\ \mbox{subject to } \ & x_1 + x_2 = 100,000\\ & x_1 - 1.06 x_2 + x_3 + x_5 = 0\\ & x_1 - 1.06 x_3 + x_4 = 0\\ & x_2 \ge -20,000\\ & x_3 \ge -20,000\\ & x_4 \ge -20,000\\ & x_5 \le 50,000\\ & x_j \ge 0, \quad j = 1,5\\ & x_j \ \text{unrestricted}, \quad j = 2,3,4\\ \end{aligned}

This problem is equivalent to the following problem with a standard form:

minx (1.303x1+1.06x4+1.06x4+1.30x5)subject to  x1+x2+x2=100,000x11.06(x2+x2)+x3+x3+x5=0x11.06(x3+x3)+x4+x4=0x2x2++s1=20,000x3x3++s2=20,000x4x4++s3=20,000x5+s4=50,000xj0,j=1,5xj+,xj0,j=2,3,4sj0,j=1,2,3,4\begin{aligned} \min_{x} \ & -(1.30 \cdot 3x_1 + 1.06 x_4^+ - 1.06 x_4^- + 1.30 x_5) \\ \mbox{subject to } \ & x_1 + x_2^+ - x_2^- = 100,000\\ & x_1 - 1.06 (x_2^+ - x_2^-) + x_3^+ - x_3^- + x_5 = 0\\ & x_1 - 1.06 (x_3^+ - x_3^-) + x_4^+ - x_4^- = 0\\ & x_2^- - x_2^+ + s_1 = 20,000\\ & x_3^- - x_3^+ + s_2 = 20,000\\ & x_4^- - x_4^+ + s_3 = 20,000\\ & x_5 + s_4 = 50,000\\ & x_j \ge 0, \quad j = 1,5\\ & x_j^+, x_j^- \ge 0, \quad j = 2,3,4\\ & s_j \ge 0, \quad j = 1,2,3,4\\ \end{aligned}
# Construct parameters
rate = 1.06

# Objective function parameters
c_ex2 = np.array([1.30*3, 0, 0, 1.06, 1.30])

# Inequality constraints
A_ex2 = np.array([[1,  1,  0,  0,  0],
                  [1, -rate, 1, 0, 1],
                  [1, 0, -rate, 1, 0]])
b_ex2 = np.array([100_000, 0, 0])

# Bounds on decision variables
bounds_ex2 = [(  0,    None),
              (-20_000, None),
              (-20_000, None),
              (-20_000, None),
              (  0,   50_000)]

Let’s solve the problem and check the status using success attribute.

# Solve the problem
res_ex2 = linprog(-c_ex2, A_eq=A_ex2, b_eq=b_ex2,
                  bounds=bounds_ex2)

if res_ex2.success:
    # We use negative sign to get the optimal value (maximized value)
    print('Optimal Value:', -res_ex2.fun)
    x1_sol = round(res_ex2.x[0], 3)
    x2_sol = round(res_ex2.x[1], 3)
    x3_sol = round(res_ex2.x[2], 3)
    x4_sol = round(res_ex2.x[3], 3)
    x5_sol = round(res_ex2.x[4], 3)
    print(f'(x1, x2, x3, x4, x5): {x1_sol, x2_sol, x3_sol, x4_sol, x5_sol}')
else:
    print('The problem does not have an optimal solution.')
Optimal Value: 141018.24349792697
(x1, x2, x3, x4, x5): (np.float64(24927.755), np.float64(75072.245), np.float64(4648.825), np.float64(-20000.0), np.float64(50000.0))

SciPy tells us that the best investment strategy is:

  1. At the beginning of the first year, the mutual fund should buy $24,927.75 \$24,927.75 of the annuity. Its bank account balance should be $75,072.25 \$75,072.25.

  2. At the beginning of the second year, the mutual fund should buy $50,000 \$50,000 of the corporate bond and keep invest in the annuity. Its bank account balance should be $4,648.83 \$ 4,648.83.

  3. At the beginning of the third year, the mutual fund should borrow $20,000 \$20,000 from the bank and invest in the annuity.

  4. At the end of the third year, the mutual fund will get payouts from the annuity and corporate bond and repay its loan from the bank. At the end it will own $141,018.24 \$141,018.24 , so that it’s total net rate of return over the three periods is 41.02% 41.02\% .

36.5Exercises

Solution to Exercise 1

So we can reformulate the problem as:

maxx1,x2 z=3x1+4x2subject to  2x1+5x2304x1+2x220x1x2x1,x20\begin{aligned} \max_{x_1,x_2} \ & z = 3 x_1 + 4 x_2 \\ \mbox{subject to } \ & 2 x_1 + 5 x_2 \le 30 \\ & 4 x_1 + 2 x_2 \le 20 \\ & x_1 \ge x_2 \\ & x_1, x_2 \ge 0 \\ \end{aligned}
# Instantiate a GLOP(Google Linear Optimization Package) solver
solver = pywraplp.Solver.CreateSolver('GLOP')

# Create the two variables and let them take on any non-negative value.
x1 = solver.NumVar(0, solver.infinity(), 'x1')
x2 = solver.NumVar(0, solver.infinity(), 'x2')
# Constraint 1: 2x_1 + 5x_2 <= 30.0
solver.Add(2 * x1 + 5 * x2 <= 30.0)

# Constraint 2: 4x_1 + 2x_2 <= 20.0
solver.Add(4 * x1 + 2 * x2 <= 20.0)

# Constraint 3: x_1 >= x_2
solver.Add(x1 >= x2)
<ortools.linear_solver.pywraplp.Constraint; proxy of <Swig Object of type 'operations_research::MPConstraint *' at 0x7fb58b752a60> >
# Objective function: 3x_1 + 4x_2
solver.Maximize(3 * x1 + 4 * x2)
# Solve the system.
status = solver.Solve()

if status == pywraplp.Solver.OPTIMAL:
    print('Objective value =', solver.Objective().Value())
    x1_sol = round(x1.solution_value(), 2)
    x2_sol = round(x2.solution_value(), 2)
    print(f'(x1, x2): ({x1_sol}, {x2_sol})')
else:
    print('The problem does not have an optimal solution.')
Objective value = 23.333333333333336
(x1, x2): (3.33, 3.33)
Solution to Exercise 2

Let us assume the carpenter produces xx units of AA and yy units of BB.

So we can formulate the problem as:

maxx,y z=23x+10ysubject to  x+y202x+0.8y25\begin{aligned} \max_{x,y} \ & z = 23 x + 10 y \\ \mbox{subject to } \ & x + y \le 20 \\ & 2 x + 0.8 y \le 25 \\ \end{aligned}
# Instantiate a GLOP(Google Linear Optimization Package) solver
solver = pywraplp.Solver.CreateSolver('GLOP')

Let’s create two variables x1x_1 and x2x_2 such that they can only have nonnegative values.

# Create the two variables and let them take on any non-negative value.
x = solver.NumVar(0, solver.infinity(), 'x')
y = solver.NumVar(0, solver.infinity(), 'y')
# Constraint 1: x + y <= 20.0
solver.Add(x + y <= 20.0)

# Constraint 2: 2x + 0.8y <= 25.0
solver.Add(2 * x + 0.8 * y <= 25.0)
<ortools.linear_solver.pywraplp.Constraint; proxy of <Swig Object of type 'operations_research::MPConstraint *' at 0x7fb58b7d02a0> >
# Objective function: 23x + 10y
solver.Maximize(23 * x + 10 * y)
# Solve the system.
status = solver.Solve()

if status == pywraplp.Solver.OPTIMAL:
    print('Maximum Profit =', solver.Objective().Value())
    x_sol = round(x.solution_value(), 3)
    y_sol = round(y.solution_value(), 3)
    print(f'(x, y): ({x_sol}, {y_sol})')
else:
    print('The problem does not have an optimal solution.')
Maximum Profit = 297.5
(x, y): (7.5, 12.5)
References
  1. Bertsimas, J. N., D. &. Tsitsiklis. (1997). Introduction to linear optimization. Athena Scientific.
  2. Hu, Y., Y. &. Guo. (2018). Operations research (5th ed.). Tsinghua University Press.
CC-BY-SA-4.0

Creative Commons License – This work is licensed under a Creative Commons Attribution-ShareAlike 4.0 International.