def medium_blp_simulation() -> SimulationFixture: """Solve a simulation with four markets, linear/nonlinear/cost constants, two linear characteristics, two cost characteristics, a demographic interacted with second-degree prices, and an alternative ownership structure. """ id_data = build_id_data(T=4, J=25, F=6) simulation = Simulation( product_formulations=(Formulation('1 + x + y'), Formulation('1 + I(prices ** 2)'), Formulation('1 + a + b')), beta=[1, 2, 1], sigma=[ [0.5, 0], [0.0, 0], ], gamma=[1, 1, 2], product_data={ 'market_ids': id_data.market_ids, 'firm_ids': id_data.firm_ids, 'clustering_ids': np.random.RandomState(1).choice(range(20), id_data.size), 'ownership': build_ownership( id_data, lambda f, g: 1 if f == g else (0.1 if f > 3 and g > 3 else 0)) }, agent_formulation=Formulation('0 + f'), pi=[[+0], [-3]], integration=Integration('product', 4), xi_variance=0.0001, omega_variance=0.0001, correlation=0.8, seed=1) return simulation, simulation.solve()
def medium_simulation(): """Solve a simulation with four markets, a nonlinear/cost constant, two linear characteristics, two cost characteristics, a demographic interacted with prices, a double acquisition, and a non-standard ownership structure. """ id_data = build_id_data(T=4, J=25, F=6, mergers=[{f: 2 for f in range(2)}]) simulation = Simulation( product_formulations=( Formulation('0 + x + y'), Formulation('1 + prices'), Formulation('1 + a + b') ), beta=[2, 1], sigma=[ [0.5, 0], [0, 0], ], gamma=[1, 1, 2], product_data={ 'market_ids': id_data.market_ids, 'firm_ids': id_data.firm_ids, 'ownership': build_ownership(id_data, lambda f, g: 1 if f == g else (0.1 if f > 3 and g > 3 else 0)) }, agent_formulation=Formulation('0 + f'), pi=[ [ 0], [-3] ], integration=Integration('product', 4), xi_variance=0.0001, omega_variance=0.0001, correlation=0.8, seed=1 ) return simulation, simulation.solve()
def test_merger(simulated_problem: SimulatedProblemFixture, ownership: bool, compute_prices_options: Options) -> None: """Test that prices and shares simulated under changed firm IDs are reasonably close to prices and shares computed from the results of a solved problem. In particular, test that unchanged prices and shares are farther from their simulated counterparts than those computed by approximating a merger, which in turn are farther from their simulated counterparts than those computed by fully solving a merger. Also test that simple acquisitions increase HHI. These inequalities are only guaranteed because of the way in which the simulations are configured. """ simulation, simulation_results, _, _, results = simulated_problem # create changed ownership or firm IDs associated with a merger merger_ids = merger_ownership = None product_data = simulation_results.product_data if ownership: merger_ownership = build_ownership( product_data, lambda f, g: 1 if f == g or (f < 2 and g < 2) else 0) else: merger_ids = np.where(product_data.firm_ids < 2, 0, product_data.firm_ids) # get changed prices and shares changed_product_data = simulation.solve(merger_ids, merger_ownership).product_data # solve for approximate and actual changed prices and shares approximated_prices = results.compute_approximate_prices( merger_ids, merger_ownership) estimated_prices = results.compute_prices(merger_ids, merger_ownership, **compute_prices_options) approximated_shares = results.compute_shares(approximated_prices) estimated_shares = results.compute_shares(estimated_prices) # test that estimated prices are closer to changed prices than approximate prices approximated_prices_error = np.linalg.norm(changed_product_data.prices - approximated_prices) estimated_prices_error = np.linalg.norm(changed_product_data.prices - estimated_prices) np.testing.assert_array_less(estimated_prices_error, approximated_prices_error, verbose=True) # test that estimated shares are closer to changed shares than approximate shares approximated_shares_error = np.linalg.norm(changed_product_data.shares - approximated_shares) estimated_shares_error = np.linalg.norm(changed_product_data.shares - estimated_shares) np.testing.assert_array_less(estimated_shares_error, approximated_shares_error, verbose=True) # test that median HHI increases if not ownership: hhi = results.compute_hhi() changed_hhi = results.compute_hhi(merger_ids, estimated_shares) np.testing.assert_array_less(np.median(hhi), np.median(changed_hhi), verbose=True)
def medium_blp_simulation() -> SimulationFixture: """Solve a simulation with four markets, linear/nonlinear/cost constants, two linear characteristics, two cost characteristics, a demographic interacted with second-degree prices, an alternative ownership structure, and a scaled epsilon. """ id_data = build_id_data(T=10, J=25, F=6) simulation = Simulation( product_formulations=(Formulation('1 + x + prices'), Formulation('1 + I(prices**2)'), Formulation('1 + a + b')), product_data={ 'market_ids': id_data.market_ids, 'firm_ids': id_data.firm_ids, 'clustering_ids': np.random.RandomState(1).choice(range(20), id_data.size), 'ownership': build_ownership( id_data, lambda f, g: 1 if f == g else (0.1 if f > 3 and g > 3 else 0)) }, beta=[1, 2, -3], sigma=[ [0.5, 0], [0.0, 0], ], pi=[[+0.0], [-0.1]], gamma=[1, 1, 2], agent_formulation=Formulation('0 + f'), integration=Integration('product', 4), xi_variance=0.00001, omega_variance=0.00001, correlation=0.8, epsilon_scale=0.7, seed=1, ) simulation_results = simulation.replace_endogenous() simulated_micro_moments = simulation_results.replace_micro_moment_values([ MicroMoment( name="demographic interaction", dataset=MicroDataset( name="inside", observations=simulation.N, compute_weights=lambda _, p, a: np.ones((a.size, p.size)), market_ids=[simulation.unique_market_ids[2]], ), value=0, compute_values=lambda _, p, a: p.X2[:, [0]].T * a. demographics[:, [0]], ) ]) return simulation, simulation_results, {}, simulated_micro_moments
def test_merger(simulated_problem: SimulatedProblemFixture, ownership: bool, solve_options: Options) -> None: """Test that prices and shares simulated under changed firm IDs are reasonably close to prices and shares computed from the results of a solved problem. In particular, test that unchanged prices and shares are farther from their simulated counterparts than those computed by approximating a merger, which in turn are farther from their simulated counterparts than those computed by fully solving a merger. Also test that simple acquisitions increase HHI. These inequalities are only guaranteed because of the way in which the simulations are configured. Finally, test that we get the same results when we initialize a solve a simulation instead of using the convenient results methods. """ simulation, simulation_results, problem, _, results = simulated_problem # create changed ownership or firm IDs associated with a merger merger_ids = merger_ownership = None product_data = simulation_results.product_data if ownership: merger_ownership = build_ownership(product_data, lambda f, g: 1 if f == g or (f < 2 and g < 2) else 0) else: merger_ids = np.where(product_data.firm_ids < 2, 0, product_data.firm_ids) # get changed prices and shares changed_product_data = simulation.solve(merger_ids, merger_ownership).product_data # compute marginal costs and create a simulation with the results costs = results.compute_costs() results_simulation = Simulation( product_formulations=simulation.product_formulations[:2], product_data=simulation_results.product_data, beta=results.beta, sigma=results.sigma, pi=results.pi, rho=results.rho, agent_formulation=simulation.agent_formulation, agent_data=simulation.agent_data, xi=results.xi, costs=costs ) # solve for actual and approximate changed prices and shares estimated = results_simulation.solve(merger_ids, merger_ownership, problem.products.prices, **solve_options) estimated_prices = results.compute_prices(merger_ids, merger_ownership, costs, **solve_options) approximated_prices = results.compute_approximate_prices(merger_ids, merger_ownership, costs) estimated_shares = results.compute_shares(estimated_prices) approximated_shares = results.compute_shares(approximated_prices) # test that estimated prices are closer to changed prices than approximate prices approximated_prices_error = np.linalg.norm(changed_product_data.prices - approximated_prices) estimated_prices_error = np.linalg.norm(changed_product_data.prices - estimated_prices) np.testing.assert_array_less(estimated_prices_error, approximated_prices_error, verbose=True) # test that estimated shares are closer to changed shares than approximate shares approximated_shares_error = np.linalg.norm(changed_product_data.shares - approximated_shares) estimated_shares_error = np.linalg.norm(changed_product_data.shares - estimated_shares) np.testing.assert_array_less(estimated_shares_error, approximated_shares_error, verbose=True) # test that median HHI increases if not ownership: hhi = results.compute_hhi() changed_hhi = results.compute_hhi(merger_ids, estimated_shares) np.testing.assert_array_less(np.median(hhi), np.median(changed_hhi), verbose=True) # test that we get the same results from solving the simulation np.testing.assert_allclose(estimated_prices, estimated.product_data.prices, atol=1e-14, rtol=0, verbose=True) np.testing.assert_allclose(estimated_shares, estimated.product_data.shares, atol=1e-14, rtol=0, verbose=True)
def medium_blp_simulation() -> SimulationFixture: """Solve a simulation with four markets, linear/nonlinear/cost constants, two linear characteristics, two cost characteristics, a demographic interacted with second-degree prices, an alternative ownership structure, and a scaled epsilon. """ id_data = build_id_data(T=4, J=25, F=6) simulation = Simulation( product_formulations=(Formulation('1 + x + y'), Formulation('1 + I(prices**2)'), Formulation('1 + a + b')), product_data={ 'market_ids': id_data.market_ids, 'firm_ids': id_data.firm_ids, 'clustering_ids': np.random.RandomState(1).choice(range(20), id_data.size), 'ownership': build_ownership( id_data, lambda f, g: 1 if f == g else (0.1 if f > 3 and g > 3 else 0)) }, beta=[1, 2, 1], sigma=[ [0.5, 0], [0.0, 0], ], pi=[[+0], [-3]], gamma=[1, 1, 2], agent_formulation=Formulation('0 + f'), integration=Integration('product', 4), xi_variance=0.0001, omega_variance=0.0001, correlation=0.8, epsilon_scale=0.7, seed=1, ) simulation_results = simulation.replace_endogenous() simulated_micro_moments = [ DemographicCovarianceMoment( X2_index=0, demographics_index=0, value=0, observations=simulation.N, market_ids=[simulation.unique_market_ids[2]]) ] return simulation, simulation_results, {}, simulated_micro_moments