Source code for equilibria.calibration.leontief
"""Leontief calibration for intermediate inputs.
Calibrates input-output coefficients from SAM data.
"""
from typing import Any
import numpy as np
from pydantic import Field
from equilibria.babel import SAM
from equilibria.calibration.base import CalibrationResult, Calibrator
from equilibria.model import Model
[docs]
class LeontiefCalibrator(Calibrator):
"""Calibrator for Leontief intermediate inputs.
Computes input-output coefficients from SAM data.
The Leontief function is:
XST[i,j] = a_io[i,j] * Z[j]
Where:
- XST[i,j] = intermediate demand for commodity i by sector j
- Z[j] = total output of sector j
- a_io[i,j] = input-output coefficient
The coefficient is computed as:
a_io[i,j] = XST[i,j] / Z[j]
Attributes:
min_coefficient: Minimum threshold for IO coefficients
"""
name: str = Field(default="Leontief", description="Calibrator name")
description: str = Field(
default="Leontief intermediate input calibration", description="Description"
)
min_coefficient: float = Field(
default=1e-10, ge=0, description="Minimum IO coefficient threshold"
)
[docs]
def calibrate(
self,
model: Model,
sam: SAM,
elasticities: dict[str, float] | None = None,
) -> CalibrationResult:
"""Calibrate Leontief IO coefficients from SAM.
Args:
model: Model with Leontief blocks
sam: SAM data
elasticities: Not used for Leontief (no elasticities)
Returns:
CalibrationResult with a_io coefficients
"""
result = CalibrationResult()
# Validate SAM
self.validate_sam(sam)
# Get sets from model
commodities = list(model.set_manager.get("I").iter_elements())
sectors = list(model.set_manager.get("J").iter_elements())
n_comm = len(commodities)
n_sectors = len(sectors)
result.add_message(
f"Calibrating Leontief for {n_comm} commodities, {n_sectors} sectors"
)
# Initialize IO coefficient matrix
a_io = np.zeros((n_comm, n_sectors))
# Compute IO coefficients
for j_idx, sector in enumerate(sectors):
# Compute total output for this sector
# Z[j] = sum of all outputs from sector j
total_output = 0.0
# Intermediate demand (from other sectors)
for i_idx, comm in enumerate(commodities):
intermediate = self.get_sam_value(sam, comm, sector)
total_output += intermediate
# Final demand (households, government, exports, etc.)
for account in sam.data.index:
if account not in commodities:
final_demand = self.get_sam_value(sam, account, sector)
total_output += final_demand
if total_output <= 0:
result.add_warning(f"Zero output for sector {sector}")
continue
# Compute IO coefficients
for i_idx, comm in enumerate(commodities):
intermediate = self.get_sam_value(sam, comm, sector)
# a_io[i,j] = intermediate demand / total output
if intermediate > 0:
coeff = intermediate / total_output
a_io[i_idx, j_idx] = max(coeff, self.min_coefficient)
# Store results
result.parameters["a_io"] = a_io
result.statistics["n_commodities"] = n_comm
result.statistics["n_sectors"] = n_sectors
result.statistics["nonzero_coeffs"] = int(np.sum(a_io > 0))
result.statistics["total_coeffs"] = n_comm * n_sectors
result.add_message("Leontief calibration completed successfully")
return result
[docs]
def get_info(self) -> dict[str, Any]:
"""Get calibrator info."""
return {
"name": self.name,
"description": self.description,
"min_coefficient": self.min_coefficient,
"calibrated_parameters": ["a_io"],
}