mergeron.core.guidelines_boundary_functions

Helper functions for defining and analyzing boundaries for Guidelines standards.

Module Contents

class mergeron.core.guidelines_boundary_functions.DiversionShareBoundaryKeywords[source]

Bases: TypedDict

Keyword arguments for functions generating share ratio boundaries.

recapture_form : Literal['inside-out', 'proportional'][source]
dps : int[source]
agg_method : Literal['arithmetic mean', 'geometric mean', 'distance'][source]
weighting : Literal['own-share', 'cross-product-share', None][source]
mergeron.core.guidelines_boundary_functions.dh_area(_delta_bound=0.01, /, *, dps=9)[source]

Area under the ΔHHI boundary.

When the given ΔHHI bound matches a Guidelines standard, the area under the boundary is half the intrinsic clearance rate for the ΔHHI safeharbor.

Notes

To derive the knots, \((s^0_1, s^1_1), (s^1_1, s^0_1)\) of the ΔHHI boundary, i.e., the points where it intersects the merger-to-monopoly boundary, solve

\[\begin{split}2 s1 s_2 &= ΔHHI \\ s_1 + s_2 &= 1\end{split}\]
Parameters:
_delta_bound : float | mergeron.core.MPFloat

Change in concentration.

dps : int

Specified precision in decimal places.

Returns:

Area under ΔHHI boundary.

Return type:

float

mergeron.core.guidelines_boundary_functions.hhi_delta_boundary(_delta_bound=0.01, /, *, dps=5)[source]

Generate the list of share combination on the ΔHHI boundary.

Parameters:
_delta_bound : float | decimal.Decimal | mergeron.core.MPFloat

Merging-firms’ ΔHHI bound.

dps : int

Number of decimal places for rounding reported shares.

Returns:

Array of share-pairs, area under boundary.

Return type:

mergeron.core.GuidelinesBoundary

mergeron.core.guidelines_boundary_functions.hhi_pre_contrib_boundary(_hhi_bound=0.03125, /, *, dps=5)[source]

Share combinations on the premerger HHI contribution boundary.

Parameters:
_hhi_bound : float | decimal.Decimal | mergeron.core.MPFloat

Merging-firms’ pre-merger HHI contribution bound.

dps : int

Number of decimal places for rounding reported shares.

Returns:

Array of share-pairs, area under boundary.

Return type:

mergeron.core.GuidelinesBoundary

mergeron.core.guidelines_boundary_functions.combined_share_boundary(_s_intcpt=0.0625, /, *, dps=10)[source]

Share combinations on the merging-firms’ combined share boundary.

Assumes symmetric merging-firm margins. The combined-share is congruent to the post-merger HHI contribution boundary, as the post-merger HHI bound is the square of the combined-share bound.

Parameters:
_s_intcpt : float | decimal.Decimal | mergeron.core.MPFloat

Merging-firms’ combined share.

dps : int

Number of decimal places for rounding reported shares.

Returns:

Array of share-pairs, area under boundary.

Return type:

mergeron.core.GuidelinesBoundary

mergeron.core.guidelines_boundary_functions.hhi_post_contrib_boundary(_hhi_bound=0.8, /, *, dps=10)[source]

Share combinations on the postmerger HHI contribution boundary.

The post-merger HHI contribution boundary is identical to the combined-share boundary.

Parameters:
_hhi_bound : float | decimal.Decimal | mergeron.core.MPFloat

Merging-firms’ pre-merger HHI contribution bound.

dps : int

Number of decimal places for rounding reported shares.

Returns:

Array of share-pairs, area under boundary.

Return type:

mergeron.core.GuidelinesBoundary

mergeron.core.guidelines_boundary_functions.diversion_share_boundary_wtd_avg(_delta_star=0.075, _r_val=DEFAULT_REC_RATIO, /, *, agg_method='arithmetic mean', weighting='own-share', recapture_form='inside-out', dps=5)[source]

Share combinations on the share-weighted average diversion share boundary.

Parameters:
_delta_star : float

Diversion share, \(\overline{d} / \overline{r}\) or \(\overline{g} / (m^* \cdot \overline{r})\).

_r_val : float

Recapture ratio.

agg_method : Literal['arithmetic mean', 'geometric mean', 'distance']

Whether “arithmetic mean”, “geometric mean”, or “distance”.

weighting : Literal['own-share', 'cross-product-share', None]

Whether “own-share” or “cross-product-share” (or None for simple, unweighted average).

recapture_form : Literal['inside-out', 'proportional']

Whether recapture-ratio is MNL-consistent (“inside-out”) or has fixed value for both merging firms (“proportional”).

dps : int

Number of decimal places for rounding returned shares and area.

Returns:

Array of share-pairs, area under boundary.

Return type:

mergeron.core.GuidelinesBoundary

Notes

An analytical expression for the share-weighted arithmetic mean boundary is derived and plotted from y-intercept to the ray of symmetry as follows:

from sympy import plot as symplot, solve, symbols
s_1, s_2 = symbols("s_1 s_2", positive=True)

g_val, r_val, m_val = 0.06, 0.80, 0.30
delta_star = g_val / (r_val * m_val)

# recapture_form == "inside-out"
oswag = solve(
    s_1 * s_2 / (1 - s_1)
    + s_2 * s_1 / (1 - (r_val * s_2 + (1 - r_val) * s_1))
    - (s_1 + s_2) * delta_star,
    s_2
)[0]
symplot(
    oswag,
    (s_1, 0., d_hat / (1 + d_hat)),
    ylabel=s_2
)

cpswag = solve(
    s_2 * s_2 / (1 - s_1)
    + s_1 * s_1 / (1 - (r_val * s_2 + (1 - r_val) * s_1))
    - (s_1 + s_2) * delta_star,
    s_2
)[1]
symplot(
    cpwag,
    (s_1, 0.0, d_hat / (1 + d_hat)), ylabel=s_2
)

# recapture_form == "proportional"
oswag = solve(
    s_1 * s_2 / (1 - s_1)
    + s_2 * s_1 / (1 - s_2)
    - (s_1 + s_2) * delta_star,
     s_2
)[0]
symplot(
    oswag,
    (s_1, 0., d_hat / (1 + d_hat)),
    ylabel=s_2
)

cpswag = solve(
    s_2 * s_2 / (1 - s_1)
    + s_1 * s_1 / (1 - s_2)
    - (s_1 + s_2) * delta_star,
     s_2
)[1]
symplot(
    cpswag,
    (s_1, 0.0, d_hat / (1 + d_hat)),
    ylabel=s_2
)
mergeron.core.guidelines_boundary_functions.diversion_share_boundary_xact_avg(_delta_star=0.075, _r_val=DEFAULT_REC_RATIO, /, *, recapture_form='inside-out', dps=5)[source]

Share combinations for the exact average diversion share boundary.

Notes

An analytical expression for the exact average boundary is derived and plotted from the y-intercept to the ray of symmetry as follows:

from sympy import latex, plot as symplot, solve, symbols

s_1, s_2 = symbols("s_1 s_2")

g_val, r_val, m_val = 0.06, 0.80, 0.30
d_hat = g_val / (r_val * m_val)

# recapture_form = "inside-out"
sag = solve(
    (s_2 / (1 - s_1))
    + (s_1 / (1 - (r_val * s_2 + (1 - r_val) * s_1)))
    - 2 * d_hat,
    s_2
)[0]
symplot(
    sag,
    (s_1, 0., d_hat / (1 + d_hat)),
    ylabel=s_2
)

# recapture_form = "proportional"
sag = solve((s_2/(1 - s_1)) + (s_1/(1 - s_2)) - 2 * d_hat, s_2)[0]
symplot(
    sag,
    (s_1, 0., d_hat / (1 + d_hat)),
    ylabel=s_2
)
Parameters:
_delta_star : float

Diversion share, \(\overline{d} / \overline{r}\) or \(\overline{g} / (m^* \cdot \overline{r})\).

_r_val : float

Recapture ratio.

recapture_form : Literal['inside-out', 'proportional']

Whether recapture-ratio is MNL-consistent (“inside-out”) or has fixed value for both merging firms (“proportional”).

dps : int

Number of decimal places for rounding returned shares.

Returns:

Array of share-pairs, area under boundary, area under boundary.

Return type:

mergeron.core.GuidelinesBoundary

mergeron.core.guidelines_boundary_functions.diversion_share_boundary_min(_delta_star=0.075, _r_val=DEFAULT_REC_RATIO, /, *, recapture_form='inside-out', dps=10)[source]

Share combinations on the minimum diversion-ratio/share-ratio boundary.

Notes

With symmetric merging-firm margins, the maximum GUPPI boundary is defined by the diversion ratio from the smaller merging-firm to the larger one, and is hence unaffected by the method of estimating the diversion ratio for the larger firm.

Parameters:
_delta_star : float

Diversion share, \(\overline{d} / \overline{r}\) or \(\overline{g} / (m^* \cdot \overline{r})\).

_r_val : float

Recapture ratio.

recapture_form : str

Whether recapture-ratio is MNL-consistent (“inside-out”) or has fixed value for both merging firms (“proportional”).

dps : int

Number of decimal places for rounding returned shares.

Returns:

Array of share-pairs, area under boundary.

Return type:

mergeron.core.GuidelinesBoundary

mergeron.core.guidelines_boundary_functions.diversion_share_boundary_max(_delta_star=0.075, _=DEFAULT_REC_RATIO, /, *, dps=10)[source]

Share combinations on the minimum diversion-ratio/share-ratio boundary.

Parameters:
_delta_star : float

Diversion share, \(\overline{d} / \overline{r}\) or \(\overline{g} / (m^* \cdot \overline{r})\).

_ : float

Placeholder for recapture ratio included for consistency with other share-ratio boundary functions.

dps : int

Number of decimal places for rounding returned shares.

Returns:

Array of share-pairs, area under boundary.

Return type:

mergeron.core.GuidelinesBoundary

mergeron.core.guidelines_boundary_functions.lerp(_x1, _x2, _r=0.25, /)[source]

From the function of the same name in the C++ standard [1]. Also, [2].

Constructs the weighted average, \(w_1 x_1 + w_2 x_2\), where \(w_1 = 1 - r\) and \(w_2 = r\).

Parameters:
_x1 : lerp.LerpT

Interpolation bounds \(x_1, x_2\).

_x2 : lerp.LerpT

Interpolation bounds \(x_1, x_2\).

_r : float | mergeron.core.MPFloat

Interpolation weight \(r\) assigned to \(x_2\)

Returns:

The linear interpolation, or weighted average, \(x_1 + r \cdot (x_2 - x_1) \equiv (1 - r) \cdot x_1 + r \cdot x_2\).

Raises:

ValueError – If the interpolation weight is not in the interval, \([0, 1]\).

Return type:

lerp.LerpT

References

mergeron.core.guidelines_boundary_functions.round_cust(_num=0.060215, /, *, frac=0.005, rounding_mode='ROUND_HALF_UP')[source]

Round to given fraction; the nearest 0.5% by default.

Parameters:
_num : float | decimal.Decimal | mergeron.core.MPFloat

Number to be rounded.

frac : float

Fraction to be rounded to.

rounding_mode : str

Rounding mode, as defined in the decimal package.

Returns:

The given number, rounded as specified.

Raises:

ValueError – If rounding mode is not defined in the decimal package.

Return type:

float

Notes

Integer-round the quotient, (_num / frac) using the specified rounding mode. Return the product of the rounded quotient times the specified precision, frac.

mergeron.core.guidelines_boundary_functions.boundary_plot(_plt, *, mktshare_plot_flag=True, mktshare_axes_flag=True, backend='pgf')[source]

Set up basic figure and axes for plots of safe harbor boundaries.

See, https://matplotlib.org/stable/tutorials/text/pgf.html