Cournot-Functions {antitrust} | R Documentation |
Multi-product Cournot/Stackelberg Calibration and Merger Simulation With Linear or Log-Linear Demand
Description
Calibrates consumer demand for multiple products using either a linear or log-linear demand system and then simulates the prices effect of a merger between two multi-plant firms under the assumption that all firms in the market are playing either a Cournot or Stackelberg quantity setting game.
Let k denote the number of products and n denote the number of plants below.
Usage
cournot(
prices,
quantities,
margins = matrix(NA_real_, nrow(quantities), ncol(quantities)),
demand = rep("linear", length(prices)),
cost = rep("linear", nrow(quantities)),
mcfunPre = list(),
mcfunPost = mcfunPre,
vcfunPre = list(),
vcfunPost = vcfunPre,
capacitiesPre = rep(Inf, nrow(quantities)),
capacitiesPost = capacitiesPre,
productsPre = !is.na(quantities),
productsPost = productsPre,
ownerPre,
ownerPost,
mktElast = rep(NA_real_, length(prices)),
mcDelta = rep(0, nrow(quantities)),
quantityStart = as.vector(quantities),
control.slopes,
control.equ,
labels,
...
)
stackelberg(
prices,
quantities,
margins,
demand = rep("linear", length(prices)),
cost = rep("linear", nrow(quantities)),
isLeaderPre = matrix(FALSE, ncol = ncol(quantities), nrow = nrow(quantities)),
isLeaderPost = isLeaderPre,
mcfunPre = list(),
mcfunPost = mcfunPre,
vcfunPre = list(),
vcfunPost = vcfunPre,
dmcfunPre = list(),
dmcfunPost = dmcfunPre,
capacitiesPre = rep(Inf, nrow(quantities)),
capacitiesPost = capacitiesPre,
productsPre = !is.na(quantities),
productsPost = productsPre,
ownerPre,
ownerPost,
mcDelta = rep(0, nrow(quantities)),
quantityStart = as.vector(quantities),
control.slopes,
control.equ,
labels,
...
)
Arguments
prices |
A length k vector product prices. |
quantities |
An n x k matrix of product quantities. All quantities must either be positive, or if the product is not produced by a plant, NA. |
margins |
An n x k matrix of product margins. All margins must be either be between 0 and 1, or NA. |
demand |
A length k character vector equal to "linear" if a product's demand curve is assumed to be linear or "log" if a product's demand curve is assumed to be log-linear. |
cost |
A length n character vector equal to "linear" if a plant's marginal cost curve is assumed to be linear or "constant" if a plant's marginal curve is assumed to be constant. Returns an error if a multi-plant firm with constant marginal costs does not have capacity constraints. |
mcfunPre |
a length n list of functions that calculate a plant's pre-merger marginal cost. If empty (the default), assumes quadratic costs. |
mcfunPost |
a length n list of functions that calculate a plant's post-merger marginal cost. If empty (the default), equals ‘mcfunPre’ |
vcfunPre |
a length n list of functions that calculate a plant's pre-merger variable cost. If empty (the default), assumes quadratic variable costs. |
vcfunPost |
a length n list of functions that calculate a plant's post-merger variable cost. If empty (the default), equals ‘vcfunPre’ |
capacitiesPre |
A length n numeric vector of pre-merger plant capacities. Default is Inf. |
capacitiesPost |
A length n numeric vector of post-merger plant capacities. Default ‘capacitiesPre’. |
productsPre |
An n x k matrix that equals TRUE if pre-merger, a plant produces a product. Default is TRUE if 'quantities' is not NA. |
productsPost |
An n x k matrix that equals TRUE if post-merger, a plant produces a product. Default equals ‘productsPre’. |
ownerPre |
EITHER a vector of length n whose values indicate which plants are commonly owned pre-merger OR an n x n matrix of pre-merger ownership shares. |
ownerPost |
EITHER a vector of length n whose values indicate which plants will be commonly owned after the merger OR an n x n matrix of post-merger ownership shares. |
mktElast |
A length k vector of product elasticities. Default is a length k vector of NAs |
mcDelta |
A length n vector where each element equals the proportional change in a firm's marginal costs due to the merger. Default is 0, which assumes that the merger does not affect any products' marginal cost. |
quantityStart |
A length k vector of quantities used as the initial guess in the nonlinear equation solver. Default is ‘quantities’. |
control.slopes |
A list of |
control.equ |
A list of |
labels |
A list with 2 elements. The first element is a vector of firm names, while the second element is a vector of products names. Default is ‘O1:On’, and ‘P1:Pk’. |
... |
Additional options to feed to the solver. See below. |
isLeaderPre |
An n x k logical matrix equal to TRUE if a firm is
a "leader" pre-merger for a particular product and FALSE otherwise.
Default is FALSE, which is equivalent to |
isLeaderPost |
An n x k logical matrix equal to TRUE if a firm
is a "leader" pre-merger for a particular product and FALSE otherwise.
Default is FALSE, which is equivalent to |
dmcfunPre |
a length n list of functions that calculate the derivative of a plant's pre-merger marginal cost. If empty (the default), assumes quadratic variable costs. |
dmcfunPost |
a length n list of functions that calculate the derivative of a plant's post-merger marginal cost. If empty (the default), equals ‘mcfunPre’ |
Details
Using price, and quantity, information for all products
in each market, as well as margin information for at least
one products in each market, cournot
is able to
recover the slopes and intercepts of either a Linear or Log-linear demand
system as well as the cost parameters (see below for further details).
These parameters are then used to simulate the price
effects of a merger between
two firms under the assumption that the firms are playing a
homogeneous products simultaneous quantity setting game.
stackelberg
, is similar to cournot
, except that for a given product,
firms are either "leaders" or "followers". leaders gain a first mover advantage
over followers, which allows the leaders to anticipate how changes to their output
will effect the follower's output decisions. Firms can be the leader for
some products but the follower in others.
‘mcfunPre’ and ‘mcfunPost’ are length n lists whose elements are ‘R’ functions
that return a firm's marginal cost. The first argument of each function should be total firm quantities.
By default, each firm is assumed to have quadratic costs with a firm-specific parameter calibrated from a firm's margin.
‘vcfunPre’ and ‘vcfunPost’ are similarly defined.
‘dmcfunPre’ and ‘dmcfunPost’ are the changes in marginal cost and are only required for stackelberg
.
‘ownerPre’ and ‘ownerPost’ values will typically be equal to either 0 (element [i,j] is not commonly owned) or 1 (element [i,j] is commonly owned), though these matrices may take on any value between 0 and 1 to account for partial ownership.
Under linear demand and linear marginal costs, an analytic solution to the Cournot quantity game
exists. However, this solution can at times produce negative
equilibrium quantities. To accommodate this issue, cournot
uses BBsolve
to
find equilibrium quantities subject to a non-negativity constraint. ...
may
be used to change the default options for BBsolve
.
Value
cournot
returns an instance of class Cournot
.
stackelberg
returns an instance of class Stackelberg
.
Author(s)
Charles Taragin ctaragin+antitrustr@gmail.com
Examples
## Simulate a Cournot merger between two single-plant firms
## producing a single product in a
## 5-firm market with linear demand and quadratic costs
n <- 5 #number of firms in market pre-merger
cap <- rnorm(n,mean = .5, sd = .1)
int <- 10
slope <- -.25
B.pre.c = matrix(slope,nrow=n,ncol=n)
diag(B.pre.c) = 2* diag(B.pre.c) - 1/cap
quantity.pre.c = rowSums(solve(B.pre.c) * -int)
price.pre.c = int + slope * sum(quantity.pre.c)
mc.pre.c = quantity.pre.c/cap
vc.pre.c = quantity.pre.c^2/(2*cap)
margin.pre.c = 1 - mc.pre.c/price.pre.c
ps.pre.c = price.pre.c*quantity.pre.c - vc.pre.c
mktQuant.pre.c = sum(quantity.pre.c)
## suppose firm 1 acquires firm 2
## This model has a closed form solution
B.post.c = B.pre.c
B.post.c[1,2] = 2*B.post.c[1,2]
B.post.c[2,1] = 2*B.post.c[2,1]
quantity.post.c = rowSums(solve(B.post.c) * -int)
price.post.c = int + slope * sum(quantity.post.c)
mc.post.c = quantity.post.c/cap
vc.post.c = quantity.post.c^2/(2*cap)
margin.post.c = 1 - mc.post.c/price.post.c
ps.post.c = price.post.c*quantity.post.c - vc.post.c
mktQuant.post.c = sum(quantity.post.c, na.rm=TRUE)
#check if merger is profitable for merging parties
isprofitable.c = ps.post.c - ps.pre.c
isprofitable.c= sum(isprofitable.c[1:2]) > 0
#prep inputs for Cournot
owner.pre <- diag(n)
owner.post <- owner.pre
owner.post[1,2] <- owner.post[2,1] <- 1
result.c <- cournot(prices = price.pre.c,quantities = as.matrix(quantity.pre.c),
margins=as.matrix(margin.pre.c),
ownerPre=owner.pre,ownerPost=owner.post)
print(result.c) # return predicted price change
summary(result.c) # summarize merger simulation
## check if 'cournot' yields the same result as closed-form solution
#print(all.equal(sum(result.c@quantityPre) , mktQuant.pre.c))
#print(all.equal(sum(result.c@quantityPost) , mktQuant.post.c))
## Simulate a Stackelberg merger between two single-plant firms
## producing a single product in a
## 5-firm market with linear demand and quadratic costs.
## Allow both merging parties to be followers pre-merger,
## but assume that they become leaders post-merger.
## Finally, assume that pre-merger, there is a single leader who ## remains a leader post-merger
## Note: This example uses setup from the above Cournot example
isLeader.pre = matrix(rep(FALSE,n), ncol=1)
isLeader.pre[n,] = TRUE
isLeader.post = isLeader.pre
isLeader.post[1:2,] = TRUE
passthru.pre = matrix(-slope^2/(2*slope - 1/cap))
passthru.post = passthru.pre
passthru.pre[isLeader.pre] = 0
passthru.post[isLeader.post] = 0
B.pre.s = matrix(slope,nrow=n,ncol=n)
diag(B.pre.s) = 2* diag(B.pre.s) - 1/cap
diag(B.pre.s)[n] = diag(B.pre.s)[n] + sum(passthru.pre)
quantity.pre.s = rowSums(solve(B.pre.s) * ( -int))
price.pre.s = int + slope * sum(quantity.pre.s)
mc.pre.s = quantity.pre.s/cap
vc.pre.s = quantity.pre.s^2/(2*cap)
margin.pre.s = 1 - mc.pre.s/price.pre.s
ps.pre.s = price.pre.s*quantity.pre.s - vc.pre.s
mktQuant.pre.s = sum(quantity.pre.s)
## suppose firm 1 acquires firm 2
## This model has a closed form solution
B.post.s = matrix(slope,nrow=n,ncol=n)
diag(B.post.s) = 2* diag(B.post.s) - 1/cap
B.post.s[1,2] = 2*B.post.s[1,2]
B.post.s[1,1:2] = B.post.s[1,1:2] + sum(passthru.post)
B.post.s[2,1] = 2*B.post.s[2,1]
B.post.s[2,1:2] = B.post.s[2,1:2] + sum(passthru.post)
diag(B.post.s)[n] = diag(B.post.s)[n] + sum(passthru.post)
quantity.post.s = rowSums(solve(B.post.s) * as.vector( -int ) )
price.post.s = int + slope * sum(quantity.post.s)
mc.post.s = quantity.post.s/cap
vc.post.s = quantity.post.s^2/(2*cap)
margin.post.s = 1 - mc.post.s/price.post.s
ps.post.s = price.post.s*quantity.post.s - vc.post.s
mktQuant.post.s = sum(quantity.post.s, na.rm=TRUE)
#check if merger is profitable for merging parties
isprofitable.s = ps.post.s - ps.pre.s
isprofitable.s = sum(isprofitable.s[1:2]) > 0
#prep inputs for Stackelberg
owner.pre <- diag(n)
owner.post <- owner.pre
owner.post[1,2] <- owner.post[2,1] <- 1
result.s <- stackelberg(prices = price.pre.s,quantities = as.matrix(quantity.pre.s),
margins=as.matrix(margin.pre.s),ownerPre=owner.pre,
ownerPost=owner.post,
isLeaderPre = isLeader.pre, isLeaderPost = isLeader.post)
print(result.s) # return predicted price change
summary(result.s) # summarize merger simulation
## check if 'stackelberg' yields the same result as closed-form solution
#print(all.equal(sum(result.s@quantityPre) , mktQuant.pre.s))
#print(all.equal(sum(result.s@quantityPost) , mktQuant.post.s))