Skip to content

🇬🇧 English · 🇪🇸 Español

Hicksian consumption welfare

Use explicit baseline and counterfactual equilibria from consistent accounting. This example runs as written on a hand-balanced two-country table:

import numpy as np
from puremacro.trade import (calibrate_trade_model, compute_hicksian_welfare,
                             solve_trade_equilibrium)

# Two countries (A, B), one good, final uses C and I, values in one currency unit.
Z = np.array([[10., 12.], [8., 14.]])
F = np.array([[30., 8., 20., 20.], [15., 15., 50., 18.]])  # to A-C, A-I, B-C, B-I
production_tax = np.array([4., 6.])
final_tax = np.array([2., 1., 3., 2.])
value_added = Z.sum(1) + F.sum(1) - Z.sum(0) - production_tax
data = np.vstack([np.hstack([Z, F]), np.r_[production_tax, final_tax],
                  np.r_[2*value_added/3, np.zeros(4)], np.r_[value_added/3, np.zeros(4)]])
calibration = calibrate_trade_model(data, ns=1, nc=2, nfd=2, country_codes=["A", "B"],
                                    sector_codes=["GOOD"])

import_rates = np.array([0.20, 0.10])  # A and B tariff RATES on all imports
tol = 1e-10  # absolute, in the table's value units; see "Tolerances" below
base = solve_trade_equilibrium(calibration, accounting="consistent", tol=tol)
counter = solve_trade_equilibrium(
    calibration, tau=import_rates, tau_fd=import_rates,
    accounting="consistent", tol=tol,
)
welfare = compute_hicksian_welfare(
    calibration, counter, base_result=base, target_country="A",
    consumption_categories=(0,),
)
print(welfare.summary())
print(welfare.to_dataframe())

Both states must converge and use the same calibration, and they must be solved with the same sigma, fiscal closure and foreign_saving_units (a mismatch raises ValueError).

Tolerances. Pass the solver tol explicitly. It bounds absolute residuals in the calibration's value units, and the welfare identities inherit that residual: with the solver default (2.5e-3) a table measured in single currency units leaves fiscal-account errors near 1e-4, which fails the fiscal identity at the welfare default tol=1e-8. Use 1e-10 for unit-scale tables like the one above and about 1e-5 to 1e-7 for the frozen OECD fixture in million USD (see consistent accounting). The welfare function re-evaluates equilibrium equations, prices, quantities and fiscal accounts using the recorded tariff schedules. Missing schedules, failed solves, stale fields and unsupported fiscal closures raise errors.

What enters utility

The default is final-use category 0, conventionally C. Within each final-use category the model has fixed origin sourcing coefficients: a Leontief basket. For multiple selected categories, preferences are Cobb–Douglas with weights omega_k = theta_k / sum_selected(theta). These weights and sourcing coefficients stay fixed across the comparison. Zero-weight categories make no contribution.

This is conditional consumption welfare. Investment (index 1 in a model with multiple final uses) is excluded. Its spending subtracts foreign saving and does not obey the consumption expenditure shares. A single-category model is supported when foreign saving is zero. A model of lifetime utility, saving or public goods would need its own preferences and intertemporal closure.

Native OECD's C category is HFCE + NPISH + GGFC. Thus its result values the model's aggregate consumption basket, including government final consumption; it is not a household-only welfare estimate. That aggregation assumption is explicit. The user may select additional non-investment categories with consumption_categories=(0, 2), declaring that they also belong in utility.

Derivation and sign

Let c_k denote the composite quantity and P_k its purchaser price, including duties and local final-use taxes. For selected positive weights omega summing to one, the utility and expenditure functions are

U(c) = product(c_k ** omega_k)
e(P, U) = U * product((P_k / omega_k) ** omega_k)
h_k(P, U) = omega_k * e(P, U) / P_k

Minimizing purchaser expenditure subject to U(c) >= U gives h_k above. Because the selected consumption budget is m = kappa * (factor income + transfers), with kappa the sum of its theta shares, observed demands satisfy P_k c_k = omega_k m. The implementation checks this duality in both states.

With 0 denoting baseline and 1 the counterfactual:

EV = e(P0, U1) - e(P0, U0)
CV = e(P1, U1) - e(P1, U0)

Both are positive for welfare gains. EV is the equivalent transfer to the selected consumption budget at baseline prices; positive CV is the amount removable from that budget at counterfactual prices while retaining baseline utility. If an income transfer must continue to follow the model's fixed consumption share kappa, the required total-income transfer is EV/kappa (or CV/kappa). The reported fields use consumption-budget units. This is the expenditure-function convention in MIT's consumer-theory notes.

The runtime evaluates utility from quantities, and expenditure from purchaser prices. It uses log ratios and expm1 for small changes. The wage-deflated Laspeyres cpi, nominal GDP and tariff receipts alone do not determine EV. No residual component is used to construct the welfare total.

ev and cv use the calibration's value units. ev_pct_consumption divides EV by baseline selected consumption expenditure; ev_pct_gdp uses baseline GDP. Neither percentage is silently substituted for the level-valued attribution. The result does not assume that every calibration is in million USD.

Exact endpoint attribution

Define A = product((P0_k/P1_k) ** omega_k), factor income F, and the solved total lump-sum transfer T. Consumption EV also equals kappa * [A*(F1+T1) - (F0+T0)] when the checked demand identities hold. Symmetrically allocating each price/income interaction gives

price_effect           = kappa * (A-1) * (F0+F1+T0+T1) / 2
factor_income_effect   = kappa * (1+A) * (F1-F0) / 2
fiscal_transfer_effect = kappa * (1+A) * (T1-T0) / 2

These expressions are the Shapley allocation across the three endpoint blocks: average each block's marginal contribution over all six possible orders. Their sum is checked against the separately calculated expenditure-function EV. The fiscal term splits into import-duty and domestic-tax rebate effects by the same weight. Those are subcomponents, not additional gains. Duties are included once in purchaser prices and once in the transfer account, as specified by the equilibrium model. A tax receipt is not itself a social welfare gain.

This attribution is conditional on the fixed model numeraire. With nonzero foreign saving the default closure (foreign_saving_units="numeraire") makes EV/CV themselves depend on which country/sector is listed first; solve both states with foreign_saving_units="world_income" for results that do not depend on the country order (see consistent accounting). Mixed endpoint blocks need not be equilibria, so it is an accounting attribution, not a causal GE experiment or a terms-of-trade/allocative-efficiency theorem. Changing nominal units consistently scales all monetary effects; the percentage EV is unchanged.

Evidence and boundaries

The independent reference solves a two-country, one-producing-sector economy with two distinct consumption baskets and a separate investment category. It then numerically minimizes origin-level purchases subject to Leontief and utility constraints at each price/utility pair. This primal optimization does not call the runtime expenditure formula. All six Shapley orderings are evaluated separately. See the reference code.

Additional checks cover identity, reversed comparisons, currency scaling, subsidies, small shocks, stale/failed states and the frozen OECD aggregation. The new interface supports the consistent model's Leontief/CES sourcing with lump-sum rebates. Tariff optimizers, Nash searches and payoff matrices now select this calculation with metric="hicksian_ev"; see policy integration and solver recovery. Historical objective aliases and flexible-model welfare proxies remain unchanged.

The library offers no TOT/Alloc/TariffRec decomposition: those fields describe a different decomposition that is not supported. Use compute_hicksian_welfare for the derived EV/CV and the attribution above.