Skip to main content

cgelab

tests license: MIT DOI

A general toolkit for SAM-based computable general equilibrium models in Python. You supply a social accounting matrix. The package calibrates a standard nested CGE from it, solves each period, runs a recursive-dynamic path and measures welfare. The accounting checks that make any of it believable are built in rather than left to the user.

A model is assembled from three separable objects, and keeping them separable is the point:

Object Says
SAM what the base year was
ModelSpec what is assumed about substitution and functional form
Closure which balances are imposed and who adjusts

Results can turn on the last two, so both travel with the results instead of living in a branch inside a solver.

Install

pip install cgelab                 # from PyPI
pip install "cgelab[parquet]"      # adds pyarrow for .parquet SAMs
pip install "cgelab[dsge]"         # adds dsgelab, for forward-looking investment
pip install "cgelab[ibge]"         # adds xlrd, for the IBGE's supply and use tables
pip install "cgelab @ git+https://github.com/GustavoHM/cgelab"   # the current main branch

For development:

git clone https://github.com/GustavoHM/cgelab && cd cgelab
pip install -e ".[test]" && pytest

Requires Python 3.11+, numpy, scipy and pandas. Try it with no data at all:

cgelab                    # runs the bundled toy economy and prints the diagnostics
cgelab my_sam.csv --sigma-armington 2.0 --sigma-va 0.5   # the same on your own SAM

Quick start

The bundled toy economy has every SAM entry written out, so the base year is known on paper and this runs as it is:

import cgelab as cge
from cgelab.examples import toy

sam, econ = toy.build()
print(cge.report(econ))           # base-year reproduction, Walras, homogeneity

base  = cge.solve_period(econ)
shock = cge.solve_period(econ, scenario=cge.Scenario(
    name="tax +50%", product_tax=econ.ptax * 1.5))
print(shock.summary())

A counterfactual over a horizon, and its welfare incidence:

growth = cge.Growth(labour=0.005, tfp=0.010, depreciation=0.05, discount=0.05)
years  = range(2021, 2046)

W   = cge.consumer_wedge(econ, {"c_ind": 0.03})
ref = cge.run_path(econ, years=years, growth=growth)
alt = cge.run_path(econ, years=years, growth=growth,
                   scenario=lambda y, t: cge.Scenario(consumer_wedge=W,
                                                      wedge_revenue_to="capital")
                                         if y >= 2026 else cge.Scenario())

ev = cge.equivalent_variation(ref, alt)
print(cge.ev_by_group(ev, {"hh_1": "rich", "hh_2": "poor"}))

With your own data, the first lines change (a .parquet SAM needs the parquet extra):

sam  = cge.SAM.read("my_sam.parquet")       # or SAM.from_long(df) / SAM.from_square(df)
sam.check_balance()                         # a hard gate, not a warning
econ = cge.calibrate(sam, cge.ModelSpec(sigma_armington=2.0, sigma_va=0.5))

Model structure

  • Production: Leontief between the intermediate bundle and value added, and within the intermediate bundle. A configurable nest (CES, Cobb–Douglas or Leontief) combines factors inside value added.
  • Make: commodity market shares are fixed at base-year proportions, so activity levels follow from commodity output, X = MSH @ Q.
  • Armington: CES between domestic and imported varieties.
  • Exports: fixed shares by default, or a CET frontier that answers to world export prices. The default is deliberate: the CET elasticity is the one parameter of a standard CGE that input–output sources do not supply.
  • Households: Cobb–Douglas or LES over commodities, out of income net of direct tax, saving and payments made straight to an activity. Income includes government transfers and net transfers from abroad.
  • Ownership: factor income is shared among households, government and the rest of the world. Returns to foreign-owned capital leave through the current account, and foreign saving is the current account, not the trade balance.
  • Factor markets: a factor is perfectly mobile, or transformed across the activities that use it by a CET or a logit, with pools of origin as a proximity matrix and a price in each activity. Labour accounts can share one population: formal and informal segments with a rigid wage, a dual market or Harris–Todaro unemployment, and income that follows each household's workers.
  • Government, investment, foreign: five closure combinations, each with its own adjusting variable (see Closure).
  • Dynamics: recursive, with one or several capital stocks accumulated from their service flows, capital by sector, putty-clay vintages, investment shared by relative rent, FDI that builds foreign-owned capital, an economy that may change year by year, and a baseline calibrated to a path of real GDP.
  • Distribution: the households of a survey, reconciled with the SAM, with poverty and inequality measures and a behavioural microsimulation.

The numeraire factor's market is deliberately not solved. It is left to Walras' law, so its residual is an independent check on the accounting rather than an identity the solver was told to satisfy. It is recorded on every period.

What is in the box

Capability Entry point
SAM container, balance gate, sign-preserving RAS; GEMPACK/GTAP header array files SAM, read_har, write_har
Calibration: coefficients, nests, taxes (tariff and output tax inside prices), margins, LES subsistence, institutional flows, a list of cells the model does not read calibrate
Within-period equilibrium; investment, government (including deficit and revenue targets), foreign and labour closures solve_period, Closure
Trade: Armington, CET, export demand and import supply curves (large country) ModelSpec
Energy: a value-added-energy or capital-energy nest with interfuel substitution, emissions accounts, a carbon price, physical units ModelSpec.energy, add_emissions, add_physical_units
Factor mobility (CET or logit, pools of origin); labour segments, dual markets and Harris–Todaro ModelSpec.factor_mobility, ModelSpec.labour_segments, LabourMarket
Counterfactuals: taxes, wedges, endowments, ownership, productivity, own-account levels, world prices, FDI, the investment basket Scenario
Recursive dynamics: several capital stocks, capital by sector, putty-clay vintages, investment allocation, foreign-owned capital, a per-year economy run_path, Growth, ModelSpec.vintages
A baseline calibrated to a path of real GDP, and policy runs at its productivity calibrate_baseline, Baseline
Microsimulation: survey households reconciled with the SAM; Gini, FGT, generalised entropy, Atkinson and their decompositions; reweighting; a behavioural model (BRR) microsimulate, inequality, poverty, Behaviour
Building a SAM from supply and use tables, with the provenance of every block; splitting households and labour by surveys; readers for the IBGE's tables, PNAD Contínua and POF sut_to_sam, split_households, split_factor, read_tru, pnadc, pof
Forward-looking investment (a Ramsey CGE solved by dsgelab) cgelab.bridge
Accounts: GDP from both sides, Laspeyres, Paasche and Fisher indices, terms of trade, the government account national_accounts, price_indices, government_account
Decompositions: subtotals by shock, Huff-Hertel welfare decomposition subtotals, welfare_decomposition
SAM multipliers, linkages, structural path analysis accounting_multipliers, linkages, structural_paths
Systematic sensitivity: Stroud quadrature and Monte Carlo over elasticities sensitivity, spec_sweep
Welfare: EV, CV and composition-immune group aggregation cgelab.welfare
Base-year reproduction, homogeneity, Walras cgelab.diagnostics
The same equilibrium as a JuMP model, for independent validation to_jump

Documentation

Verification

Every number the package produces is checked against something it did not compute itself:

  • Hand-built SAMs whose every entry is written out, so the base year is known on paper: base-year reproduction, zero-degree homogeneity and Walras' law in every closure, on every variant (margins, own-account activities, institutions, trade taxes, CET, energy nests, carbon).
  • Closed forms and published tables: Miller and Blair's Leontief inverse, the stochastic growth model (for the bridge to dsgelab), Stroud quadrature on cubics, CES first-order conditions, and the identities that hold in every equilibrium (GDP from both sides, the welfare decomposition, subtotals that add up).
  • A published model: the tariff abolition of Hosoe, Gasawa and Hashimoto's stdcge and lrgcge against a line-by-line JuMP transcription of the GAMS programs, in all 49 displayed variables, to 2.4e-12.
  • An independent replica: to_jump writes the same equilibrium as a JuMP model in which nothing is nested. validation/roundtrip_jump.py runs 50 cases; the nested solver and Ipopt agree to 1.2e-11.
pytest                                                     # the suite, without external tools
cd validation && julia --project=. -e 'using Pkg; Pkg.instantiate()' && cd ..
python validation/roundtrip_jump.py                        # the JuMP replica
python validation/replicate_hosoe.py                       # stdcge and lrgcge

Scope and known limitations

cgelab covers a single-country CGE at applied scale. It does not have the maturity of GAMS or GEMPACK, and docs/comparison.md says where it stands. Things to know before relying on it:

  • Several regions share one origin nest under the Armington. Factors do not migrate, and the regional slice refuses margins, CET, LES, trade taxes, energy nests and most closures by name. GTAP-style bilateral trade is 0.7.
  • No complementarity: activities cannot switch off, and there are no quotas, price floors or capacity limits. That is 0.8.
  • The solver uses finite-difference Jacobians on a few unknowns. It is fine up to a few hundred accounts; each commodity put on a trade curve adds an unknown, and so does each activity that uses an imperfectly mobile factor.
  • Fixed proportions everywhere (sigma_va = 0 in every activity) can leave the model without a solution under full employment of every factor.
  • Under fixed export shares with a Cobb-Douglas Armington, the exchange rate is not determined, and solve_period refuses that combination; near an Armington elasticity of one it is badly conditioned.
  • Forward-looking investment goes through dsgelab (pip install "cgelab[dsge]"). run_path itself has no forward-looking agent.
  • GTAP data can be read, but not yet aggregated or turned into a SAM, and the welfare decomposition has not been compared with GTAP's own.
  • Platforms: an editable install (pip install -e) can break silently on Python 3.14 on macOS; install from the wheel if import cgelab fails.

dsgelab, by the same author, solves dynamic stochastic general equilibrium (DSGE) models. The module cgelab.bridge uses it for the intertemporal part of a model, a Ramsey CGE in which investment follows an Euler equation (pip install "cgelab[dsge]").

Citing

If the package contributed to a published result, cite it as any other methodological input, with the version, because a number that reproduces only under one version cannot be reproduced without knowing which. CITATION.cff holds the same metadata in the format GitHub reads.

Moreira, G. H. (2026). cgelab: A general toolkit for SAM-based computable general equilibrium models in Python (Version 0.5.5) [Computer software]. Zenodo. https://doi.org/10.5281/zenodo.23458851

@software{cgelab_2026,
  author  = {Moreira, Gustavo Hoffmann},
  title   = {{cgelab}: a general toolkit for SAM-based computable general equilibrium models in Python},
  year    = {2026},
  version = {0.5.5},
  license = {MIT},
  doi     = {10.5281/zenodo.23458851},
  url     = {https://github.com/GustavoHM/cgelab},
  note    = {Python package}
}

Each release is archived on Zenodo with a DOI of its own (0.5.0: 10.5281/zenodo.23458852). The concept DOI above, 10.5281/zenodo.23458851, resolves to the latest release.

Metadata

Release files for cgelab 0.5.5

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for cgelab 0.5.5
File Size Uploaded Provenance
cgelab-0.5.5.tar.gz 321.1 kB With provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for cgelab 0.5.5
File Interpreter ABI Platform
cgelab-0.5.5-py3-none-any.whl Python 3 none any Details

Total release size: 517.9 kB

Release files / cgelab-0.5.5.tar.gz

Download URL cgelab-0.5.5.tar.gz
Size 321.1 kB
Tags Source
SHA-256 checksum
How to use checksums
e20eb57223e061735fc034e6a747a3f93235d9a09e70355bdb81ab73c83c6fd6
BLAKE2b-256 checksum
How to use checksums
199813fd22d9da3836c921c86eb1a5f3677e76f51092ee1b6964abc23ca12086
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 24, 2026.

Transparency log

Release files / cgelab-0.5.5-py3-none-any.whl

Download URL cgelab-0.5.5-py3-none-any.whl
Size 196.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
3af4f0183b4367158b33dfcb9a7dcf5dc06479f1ea3c0d4957922c681b7aea53
BLAKE2b-256 checksum
How to use checksums
f4f5c8923be59f1a963bc876511691a9ff0c6bb9281a30c3f9969891949d8e13
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 24, 2026.

Transparency log

Security for cgelab 0.5.5

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for cgelab-0.5.5.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 24, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page