# A Nonhomogeneous Production Function

This workbook considers a production function that is not homogeneous. That is, 
the ratio of inputs that equals a specified value depends on the output level.

One advantage of a nonhomogeneous function is that it can yield a long-run average
cost curve that is not monotonic. Recall that a function that is homogeneous of 
degree 1 yields a horizontal long-run average cost curve. Those with a degree 
less than one yield ever-increasing average cost. Those with a degree greater 
than one 

kill(all)$ fpprintprec:5$ ratprint:false$
xFunction: sqrt(K) * log(L+1)^1.5;

This specification is chosen because it mimics a Cobb-Douglas
function over the range of values that we consider below. Specifically,
it mimics x = sqrt(KL). To see that the two are similar, plot 
log(L+1)^1.5 and sqrt(L) over the range 0 to 100.

/*Input. Execute (ctrl-enter) for results */
wxdraw2d( user_preamble="set key left", line_width=2,
 key="(L + 1)^{1.5}", explicit(log(L+1)^1.5,L,0,100), 
 color=black, key=string(sqrt(L)),explicit(sqrt(L),L,0,100)

/*Note the use of { } to require draw to raise 1.5. Without the
  bracket, only the 1 will be raised. */

)$

## Some aspects of the function

If a function is to represent production, it should satisfy some minimal
conditions, among the following:
1.  The marginal products of the inputs should be diminishing, at least
over employment range.
2.  The marginal products of the inputs should be positive, at least until
the employment level reaches a relatively large level.
3.  The marginal product of any input should be related to the employment
level of the other input. Presumably, in most cases MPK changes in the same
direction as the employment of L (assuming that L and K are the two inputs)
and vice versa.

Confirm that the function used here satisfies all three conditions. 
First, verify that the expression for the two marginal product functions
consist entirely of positive-valued terms.

/*Input. Execute (ctrl-enter) for results *//* An answer */
/* The marginal products are positive for all values of K and L 
  */
[diff(xFunction,K), diff(xFunction,L)];

The second condition, that the second derivatives must be negative,
is not so easy to confirm. Indeed, it is correct only for values of
L greater than sqrt(%e) - 1, which is approximately 0.649, so we truncate 
the following analysis to take that limitation into account.

/*Input. Execute (ctrl-enter) for results */
/* The slopes of the marginal products are negative for all K & L */ 
[diff(xFunction,K,2), diff(xFunction,L,2)]; radcan(%);

Graph the expression 6*log(L+1)-3 over the range 0 < L < 5.
Use find_root( ) or solve( ) to determine the ranges over which this
term is positive, i. e., the range over which the marginal product 
of labor (mpl) is declining.

/*Input. Execute (ctrl-enter) for results */
wxdraw2d(title="When this is positive, mpl slopes downward",
 xaxis=true, explicit(6*log(L+1)-3,L, 0,5))$
find_root(6*log(L+1)-3,L,0,20);
/*or*/
solve(log(L+1)=1/2,L);  float(%);

Confirm that both of the cross-partial derivatives are positive.

/*Input. Execute (ctrl-enter) for results */
/* The two cross-partial derivatives (one of which is redundant),
  confirm that the marginal product of each input is directly related
  to the employment level of the other input */
[diff(xFunction,K,1,L,1), "or", diff(xFunction,L,1,K,1)];

Confirm that when both K and L equal zero, x = 0.+

/*Input. Execute (ctrl-enter) for results */subst([K=0,L=0],xFunction);

Use draw3d to graph the function over the ranges 0 <= K <=  10
and 1 <= L <= 10.

/*Input. Execute (ctrl-enter) for results */
wxdraw3d(xrange=[0,10], yrange=[0,10],
explicit(xFunction,K,0,10,L,1,10),
dimensions = [480,480])$

Copy the command above and add the option contour=map to the command
in order to produce isoquants. 

/*Input. Execute (ctrl-enter) for results */
wxdraw3d(xrange=[0,10], yrange=[0,10], contour=map,
explicit(xFunction,K,1,10,L,1,10),
dimensions = [480,480])$

Confirm that this production function is not homogeneous.

/*Input. Execute (ctrl-enter) for results */
subst([K=m*K,L=m*L],xFunction);

Confirm that the function is also not homothetic. Set K = k*L, where
k is a positive constant. Confirm that the slopes of the isoquants 
are not constant when K/L = k.

/*Input. Execute (ctrl-enter) for results */
/* 
   Define the slope of any isoquant */
diff(xFunction,L)/diff(xFunction,K);
/*Substitute K = k*L into the solution */
subst(K=k*L,%);

An important slope of isoquants is the one that equals w/r. 
Assume that r = 1 and w = 1. Determine the relationship between
K and L that is consistent with least-cost production.

The existence of such a relationship between K and L implies that,
though the function is not homothetic, we can derive a relationship
between x and total cost.

/*Input. Execute (ctrl-enter) for results */
assume(L>0,K>0)$ /* Required to avoid dialog with Maxima */

solnK: solve(diff(xFunction,L)/diff(xFunction,K)=1,K);

/*The result implies that K/L increases as L increases; i.e., 
  as the firm produces more. The function KF(L) will be used
  below in mapping this expression onto a list. */ 

KF(L):=''(rhs(%[1]));

Observe that log(L) < 0 when 0 < L < 1, so KF(L) implies a negative 
value of K. This implies that this function applies only for L > 1.
Evaluate xF(L) for these values of x: 0.5, 1.5, 15, 150. 

Confirm that as L approaches 0, both K(L) and x(L) approach 0.

/*Input. Execute (ctrl-enter) for results */

"The first row shows L, the second K, and the third x.";
matrix([1,2,20,100,200],
float(map(KF,[1,2,20,100,200])),
float(map(xF,[1,2,20,100,200])) );
limit([xF(L),KF(L)],L,0);
/*or*/
[limit(xF(L),L,0), limit(KF(L),L,0)];

Graph KF(L) to confirm that increasing L is accompanied by a 
proportionately larger increase in K, so that K/L increases,
the the mrs is to be maintained.

/*Input. Execute (ctrl-enter) for results */
wxdraw2d(xlabel = "L", ylabel = "K", 
 key = "Optimal employment of K",
 explicit(KF(L),L,1,200), color=black, 
 key = "K = L",explicit(L,L, 0,200)
 )$

## Least-cost production

The function KF(L) defines the optimal amount of capital to employ
at each level of L employment. Use that fact to create an augmented
production function which shows the relationship between x and L 
given that K/L is properly selected.

/*Input. Execute (ctrl-enter) for results */
xAugmented: subst(solnK,xFunction)$ xF(L):=''(ratsimp(%));
/* The function xF(L) will be used below in mapping onto a list.
   It displaces the xF(L) function used earlier.
*/
solnL: solve(xAugmented=x, x);

Evaluate xF(L) for these values of L: 1, 1.5, 2, 4, 20, 200.

/*Input. Execute (ctrl-enter) for results */
float(map(xF,[1, 1.5, 2, 4, 20, 200]));

Discussion:
We return to the behavior of this function when 0 < L < 1 below.

The nonhomotheteticity of this function precludes 
expressing L as a function of x. Therefore, we cannot directly derive
an explicit expression for long-run total cost (r*K + w*L) as a function
of x.

Use the implicit option in draw2d( ) to examine the long-run total 
cost function. 

/*Input. Execute (ctrl-enter) for results */
wxdraw2d(yrange=[0,70],
 xlabel= "L", ylabel = "x", xtics={1,5,25,50},
implicit(solnL[1],L,1,50,x,0,70)
)$

Discussion:
The graph shows that x increases less than proportionately with L. 
We also know that K increases more than proportionately with 
L. Therefore we can conclude that, over all ranges considered, 
long-run total cost (r*K + w*L) must increase faster than 
output does.

Create these lists: Llist is a list of i values from 10 through 100 in 
increments of 10, Klist is a list of K values given that the least-cost
K/L prevails, xlist is a list of output values given the same condition,
and ltclist is a list of ltc values (remember: ltc = 1*K + 1*L).

Create a list of L values tht range from 10 to 100 in increments of
10. Then use cons( ) to append the value 2 to the beginning of the 
list. Assign the name Llist this list of 11 values of L. Then use
map(KF,Llist) to create a list named Klist. Use a similar command to
create a list of x values, xlist.

Given that the cost per unit of both K and L is 1 (dollar), the 
list ltclist is the sum of Llist and Klist; create this list and name 
it.

/*Input. Execute (ctrl-enter) for results */
Llist: cons(2, makelist(10*i,i,1, 10))$
Klist: float(map(KF,Llist))$
xlist: float(map(xF,Llist))$
ltclist: Llist+Klist$
/*
The use of a matrix to create a table is not required.
  We also add an average cost column.
*/
transpose(matrix(Llist,Klist,xlist,ltclist, ltclist/xlist))$
addrow(matrix(["L","K","x","ltc","lac"]),%);

Use the points( ) option in wxdraw2d to graph ltc against x.

/*Input. Execute (ctrl-enter) for results */
wxdraw2d(xlabel= "x", ylabel = "$", yrange=[0,ltclist[10]],
points(xlist,ltclist)
)$

Derive an explicit expression inputcosts(L) that states total cost as a 
function of L. Be aware that inputcosts(L) is not the "long-run total 
cost function" -- the long-run total cost function is expressed
in terms of x.

/*Input. Execute (ctrl-enter) for results */
inputcosts(L):= ''(KF(L)+L);

Use the two functions xF(L) and ltc(L) in the parametric( ) option of draw( ).
Graph ltc against x.

/*Input. Execute (ctrl-enter) for results */
wxdraw2d(yrange=[0,inputcosts(50)],
 xlabel="x", ylabel = "$", key="Long-run Total Cost",
parametric(xF(L),inputcosts(L),L,1.1,50)
)$

Derive an expression for d(inputcosts)/d(x) = [d(inputcosts)/d(L)]/[d(x)/d(L)].
Do this by taking the ratio of diff(inputcosts(L),L) to diff(xF(L),L). 
Create the functional expression mic(L):= the ratio above. The name mic
refers to marginal input cost. This function defines the marginal cost at
each value of L, not of x, so it is not the long-run marginal cost curve. It
can, however, be used to graph that curve.

/*Input. Execute (ctrl-enter) for results */
diff(inputcosts(L),L) / diff(xF(L),L)$ mic(L):=''(ratsimp(%));

Construct an expression for lic(L), total input costs divided by L.
Now, we have a parametric expression for marginal cost and one for average 
cost. In both, L is the parameter. Denote these two functions as aic(L) and
mic(L).

/*Input. Execute (ctrl-enter) for results */
inputcosts(L)/xF(L)$ aic(L):= ''(ratsimp(%));

Use find_root( ) to determine the L value at which mic(L) = aic(L).
Use a graph to determine the range within which mic(L) = aic(L).

An answer
We graph the expresions over the range 0 <= L <= 10. The draw2d( )
program ignores the extreme, L = 0, that results in undefined values.
The range is clearly between 2 and 6, so we pass those values to
find_root below.

/*Input. Execute (ctrl-enter) for results */
wxdraw2d(yrange=[0,mic(70)],xrange=[0,50],
title = "Warning -- Not average and marginal cost curves",
xlabel="L -- not x", ylabel="$ per unit",
explicit(aic(L),L,0,50),
explicit(mic(L),L,0,50)
)$

/*Input. Execute (ctrl-enter) for results */
L0: find_root(mic(L)-aic(L),L,1,100);
["mic(L0) and aic(L0) values: ",float([mic(L0),minUnitCost: aic(L0)])];

Use the parametric( ) option in draw2d( ) to draw the average cost and 
marginal cost curve. 

/*Input. Execute (ctrl-enter) for results */
wxdraw2d( 
 user_preamble="set key bottom",
 title="Average and marginal cost curves",
 xlabel="x",ylabel="$ per unit",
 xrange=[0,xF(50)],yrange=[0,1.5*mic(50)],
 line_width=2,key="lac",
 parametric(xF(L),aic(L),L,0,50),
 color=red, key = "lmc",
 parametric(xF(L),mic(L),L,0,50)
)$

## Short-run production and cost

Set K = 36 and derive the short-run production function.

/*Input. Execute (ctrl-enter) for results */
xFunctionSR: subst(K=36, xFunction);

Graph this function over the range L = 2 to L = 50.

/*Input. Execute (ctrl-enter) for results */
wxdraw2d(xlabel="L",ylabel="x", xrange=[0,50],yrange=[0,50],
explicit(xFunctionSR, L, 2, 50));

Derive an expression named inputcostSR for the short-run cost stated
in terms of L.

Use parametric( ) to graph the short-run total cost curve.

/*Input. Execute (ctrl-enter) for results */
inputcostSR : 36 + 1*L;
wxdraw2d( xlabel="x", ylabel = "$", yrange = [0,100],
 parametric(xFunctionSR,inputcostSR,L,2,50)
);

Use parametric( ) again, this time to draw the short-run average
cost curve.

/*Input. Execute (ctrl-enter) for results */
wxdraw2d( yrange=[0,5],xlabel="x",ylabel="$ per unit",
 line_width=2, key = "Short-run average cost",
 parametric(xFunctionSR,inputcostSR/xFunctionSR,L,2,80),
 color=black, key = "Short-run marginal cost",
 parametric(xFunctionSR,diff(inputcostSR,L)/diff(xFunctionSR,L),L,2,80)
);

Combine the long-run and short-run per-unit curves in the same graph.
Extend therange for the short-run graphs to 2 - 100.

/*Input. Execute (ctrl-enter) for results */
wxdraw2d( 
 user_preamble="set key bottom",
 title="Average and marginal cost curves",
 xlabel="x",ylabel="$ per unit",
 xrange=[0,xF(50)],yrange=[0,1.5*mic(50)],
 line_width=2,key="lac",
 parametric(xF(L),aic(L),L,0,50),
 color=red, key = "lmc",
 parametric(xF(L),mic(L),L,0,50),color=black, key = "sac",
 parametric(xFunctionSR,inputcostSR/xFunctionSR,L,2,100),
 color=orange, key = "smc",
 parametric(xFunctionSR,diff(inputcostSR,L)/diff(xFunctionSR,L),L,2,80)
)$

Use find_root( ) to determine the value at which xF(L) = xFunctionSR.

/*Input. Execute (ctrl-enter) for results */
print("Tangency when L =", 
         tangencyL: find_root(xF(L) = xFunctionSR,L,2,200))$
print("Tangency occurs when x = ", tangencyx: float(xF(%)));
["check", subst(L = tangencyL, xFunctionSR)];

Confirm that lmc = smc at the value identified above.

/*Input. Execute (ctrl-enter) for results */
mic(L) -  diff(inputcostSR,L) / diff(xFunctionSR,L); 
float(subst(L=tangencyL,%));

Confirm that lac = sac at the value identified above.

/*Input. Execute (ctrl-enter) for results */
aic(tangencyL) - subst(L = tangencyL, inputcostSR/xFunctionSR);
float(%);

Discussion:
In both cases the differences are infinitesimal and are due to 
the approximations in find_root( ).