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 optim control parameters passed to the calibration routine optimizer (typically the calcSlopes method).

control.equ

A list of BBsolve control parameters passed to the non-linear equation solver (typically the calcQuantities method).

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 cournot.

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 cournot.

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))


[Package antitrust version 0.99.26 Index]