Constrained Optimization#

Analytical and numerical approaches#

This notebook contains some interactive graphical examples and a simple sample numerical constrained optimization. This notebook uses widgets from the ipywidgets library which will not be rendered in a static view.

Consumer’s optimization problem:#

The consumer chooses a consumption bundle \((x_0, x_1\) to solve:

\[\max_{x_0,x_1} U(x_0,x_1) \]

subject to a budget constraint

\[p \cdot x_0 + x_1 \leq I \]

where \(p=\frac{p_{0}}{p_{1}}\) is the relative price of good 0 measured in terms of units of good 1.

If we choose a Cobb-Douglas utility function of the form

\[ U(x_0, x_1) = \alpha \cdot log(x_0) + (1-\alpha) \cdot log(x_1) \]

We can solve for the Marshallian demands in a variety of ways. For example by using the binding budget constraint to substitute for \(x_1\) to solve for the uncontrained maximum in \(x_0\) in

\[ \max_{x_0} \alpha \cdot log(x_0) + (1-\alpha) \cdot log(I - p \cdot x_0) \]

The first-order necessary condition (FOC) for an interior optimum, \(\frac{\alpha}{x_0} = p \cdot \frac{1-\alpha}{I-p \cdot x_0}\), can be solved to give us the Marshallian demand function for \(x_0(p, I)\), and \(x_1(p,I)\):

\[\begin{split} \begin{aligned} x_0^* &= \alpha \cdot \frac{I}{p} \\ x_1^* &= (1-\alpha) \cdot I \end{aligned} \end{split}\]

If we substitute in prices, income and the share parameter we find the vector of Marshallian demands \([x_0^*, x_1^*]\) from which we can also find the indirect utility funtion \(V(p,I) =U(x_0^*, x_1^*)\).

We’ve written some python functions for the graphs and numerical solutions below, most of which are placed in the cd library (cd for Cobb-Douglas).

Hide code cell source
import sys
from IPython.display import display, Latex
sys.path.insert(0,'..')  
from cd import *    # import cobb douglas python library of functions
consume_plot(p=1, I=100, a = 0.6)
../../_images/cc5f505c093f0ee867e1f307576526ab603872e089a88de39d6ac2a3f5d06dd0.png

In the next cell control plot parameters with sliders (will only display if running with live kernel)

interact(consume_plot, p=(0.5,2,0.1), I=(50,150,10), a=(0.1,0.9,0.1));

Move the slider to move the consumption point along the budget line. Keep adjusting until we reach the highest indifference curve at a tangency point.

The ‘no-arbitrage’ argument#

In the diagram below we’ve guessed that the optimum is the point along the budget constraint \((x_0, x_1)=(20, 80)\) but when we check this, we verify that

\[ \frac{MU_0}{p_0} > \frac{MU_1}{p_1} \]

Since the marginal utility per dollar spent on good 0 is larger than the marginal utility per dollar spent on good 1, utility can be increased by moving some spending from good 0 to good 1.

alpha = 0.6
p = 1
I = 100
arb_plot(c0g=20, I=100, p=1)
../../_images/95cb41f92738df2156dea79a648a965c44de9e11bfb1e9108a3b74e6c79ce359.png

In the next interactive diagram, we can move the sliders (this will only change the display if running this notebook with live kernel) to find the optimum.

interact(arb_plot, c0g=(1,I,0.1), I=(50,150,10), p=fixed(1));

Numerical constrained optimization with python#

The problem we have been solving can be easily solved analytically (i.e. we can derive formulas for Marshallian demands) but it’s useful to also see how this type of constrained optimization problem can be solved numerically using the scipy.opimize library.

The demands(p, I) function takes \(p\) and \(I\) and \(\alpha\) as paramterers to maximize u (or, same, minimize -u) subject to the budget constraint using scipy’s minimize (which :

Hide code cell source
def demands(p, I, a= alpha):
    
    def budget(x):
        return np.array([p*x[0] + x[1] - I])
    
    def negU(x):
        return -u(x, a)

    x = np.array([(I/2)/p, (I/2)])  # initial guess -- spend half I on each good
    ux = minimize(negU, x, constraints = ({'type': 'eq', 'fun' : budget }) )
    return ux.x

Suppose \(p=1, I=100\) and the Cobb-Douglass share parameter is \(\alpha = 0.7\)). Demands for \(x_0\) and \(x_1\) are found to be:

[x0opt, x1opt] = demands(1, 100, 0.7)
Hide code cell source
display(Latex(f'$u(x_0^*, x_1^*)$ = {u([x0opt, x1opt], 0.7):0.1f}'))
\[$u(x_0^*, x_1^*)$ = 54.3\]

The same solution we obtain from analytical formulas:

cd_demands(1,100, 0.7)
([70.0, 30.000000000000004], 54.28814526898254)

Finally let’s setup a simple widget to let us see the consumer optimum changes with parameters.

Will only display if run with a live kernel.

interact(demands, p=(0.2,2,0.1), I = (50, 200, 10), a =(0.2, 0.8, 0.1));