cgelab 0.5.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (84) hide show
  1. cgelab-0.5.0/CHANGELOG.md +268 -0
  2. cgelab-0.5.0/CITATION.cff +24 -0
  3. cgelab-0.5.0/LICENSE +21 -0
  4. cgelab-0.5.0/MANIFEST.in +9 -0
  5. cgelab-0.5.0/PKG-INFO +252 -0
  6. cgelab-0.5.0/README.md +214 -0
  7. cgelab-0.5.0/pyproject.toml +60 -0
  8. cgelab-0.5.0/setup.cfg +4 -0
  9. cgelab-0.5.0/site/.nojekyll +0 -0
  10. cgelab-0.5.0/site/README.md +58 -0
  11. cgelab-0.5.0/site/highlight.js +38 -0
  12. cgelab-0.5.0/site/index.html +570 -0
  13. cgelab-0.5.0/site/pt-br/index.html +575 -0
  14. cgelab-0.5.0/site/pt-br/replications.html +210 -0
  15. cgelab-0.5.0/site/replications.html +213 -0
  16. cgelab-0.5.0/site/style.css +92 -0
  17. cgelab-0.5.0/src/cgelab/__init__.py +74 -0
  18. cgelab-0.5.0/src/cgelab/__main__.py +7 -0
  19. cgelab-0.5.0/src/cgelab/bridge.py +173 -0
  20. cgelab-0.5.0/src/cgelab/calibrate.py +625 -0
  21. cgelab-0.5.0/src/cgelab/cli.py +40 -0
  22. cgelab-0.5.0/src/cgelab/closure.py +163 -0
  23. cgelab-0.5.0/src/cgelab/decompose.py +431 -0
  24. cgelab-0.5.0/src/cgelab/diagnostics.py +113 -0
  25. cgelab-0.5.0/src/cgelab/dynamics.py +310 -0
  26. cgelab-0.5.0/src/cgelab/emissions.py +139 -0
  27. cgelab-0.5.0/src/cgelab/examples/__init__.py +5 -0
  28. cgelab-0.5.0/src/cgelab/examples/hosoe.py +135 -0
  29. cgelab-0.5.0/src/cgelab/examples/regions.py +70 -0
  30. cgelab-0.5.0/src/cgelab/examples/toy.py +244 -0
  31. cgelab-0.5.0/src/cgelab/export.py +820 -0
  32. cgelab-0.5.0/src/cgelab/functions.py +142 -0
  33. cgelab-0.5.0/src/cgelab/har.py +314 -0
  34. cgelab-0.5.0/src/cgelab/multipliers.py +292 -0
  35. cgelab-0.5.0/src/cgelab/physical.py +118 -0
  36. cgelab-0.5.0/src/cgelab/py.typed +0 -0
  37. cgelab-0.5.0/src/cgelab/regional.py +575 -0
  38. cgelab-0.5.0/src/cgelab/results.py +262 -0
  39. cgelab-0.5.0/src/cgelab/sam.py +177 -0
  40. cgelab-0.5.0/src/cgelab/scenario.py +181 -0
  41. cgelab-0.5.0/src/cgelab/sensitivity.py +257 -0
  42. cgelab-0.5.0/src/cgelab/solve.py +1041 -0
  43. cgelab-0.5.0/src/cgelab/spec.py +333 -0
  44. cgelab-0.5.0/src/cgelab/welfare.py +100 -0
  45. cgelab-0.5.0/src/cgelab.egg-info/PKG-INFO +252 -0
  46. cgelab-0.5.0/src/cgelab.egg-info/SOURCES.txt +82 -0
  47. cgelab-0.5.0/src/cgelab.egg-info/dependency_links.txt +1 -0
  48. cgelab-0.5.0/src/cgelab.egg-info/entry_points.txt +2 -0
  49. cgelab-0.5.0/src/cgelab.egg-info/requires.txt +12 -0
  50. cgelab-0.5.0/src/cgelab.egg-info/top_level.txt +1 -0
  51. cgelab-0.5.0/tests/conftest.py +10 -0
  52. cgelab-0.5.0/tests/data/hosoe_tariff_abolition.json +378 -0
  53. cgelab-0.5.0/tests/test_accounts.py +106 -0
  54. cgelab-0.5.0/tests/test_bridge.py +101 -0
  55. cgelab-0.5.0/tests/test_calibrate.py +73 -0
  56. cgelab-0.5.0/tests/test_cet_external.py +129 -0
  57. cgelab-0.5.0/tests/test_closures.py +96 -0
  58. cgelab-0.5.0/tests/test_decompose.py +84 -0
  59. cgelab-0.5.0/tests/test_dynamics.py +71 -0
  60. cgelab-0.5.0/tests/test_emissions.py +104 -0
  61. cgelab-0.5.0/tests/test_energy_nest.py +157 -0
  62. cgelab-0.5.0/tests/test_export.py +91 -0
  63. cgelab-0.5.0/tests/test_government_closures.py +78 -0
  64. cgelab-0.5.0/tests/test_har.py +111 -0
  65. cgelab-0.5.0/tests/test_hosoe_benchmark.py +46 -0
  66. cgelab-0.5.0/tests/test_hosoe_stdcge.py +61 -0
  67. cgelab-0.5.0/tests/test_institutions_dynamics.py +247 -0
  68. cgelab-0.5.0/tests/test_investment_mix.py +49 -0
  69. cgelab-0.5.0/tests/test_jump_roundtrip.py +66 -0
  70. cgelab-0.5.0/tests/test_labour.py +135 -0
  71. cgelab-0.5.0/tests/test_multipliers.py +156 -0
  72. cgelab-0.5.0/tests/test_period.py +162 -0
  73. cgelab-0.5.0/tests/test_physical.py +58 -0
  74. cgelab-0.5.0/tests/test_regions.py +111 -0
  75. cgelab-0.5.0/tests/test_report.py +32 -0
  76. cgelab-0.5.0/tests/test_results.py +85 -0
  77. cgelab-0.5.0/tests/test_sam.py +47 -0
  78. cgelab-0.5.0/tests/test_sensitivity.py +105 -0
  79. cgelab-0.5.0/tests/test_site_examples.py +27 -0
  80. cgelab-0.5.0/tests/test_tariff.py +195 -0
  81. cgelab-0.5.0/tests/test_trade_curves.py +139 -0
  82. cgelab-0.5.0/tests/test_welfare.py +89 -0
  83. cgelab-0.5.0/tests/test_welfare_decomposition.py +92 -0
  84. cgelab-0.5.0/tools/check_site_examples.py +83 -0
@@ -0,0 +1,268 @@
1
+ # Changelog
2
+
3
+ All notable changes to `cgelab`. Versions follow [semantic versioning](https://semver.org/);
4
+ before 1.0, a minor version may add to the API and a patch version only fixes.
5
+
6
+ ## 0.5.0 — 2026-10-18
7
+
8
+ The first public release, on PyPI together with dsgelab 0.5. It gathers the roadmap's
9
+ milestones 0.3 and 0.4, which were not released on their own, and the release engineering of
10
+ 0.5. Python 3.10 is no longer supported.
11
+
12
+ ### Changed since 0.2.0
13
+
14
+ - Renamed from `cgekit` to `cgelab`: `cgekit` is taken on PyPI by an
15
+ unrelated project. The import name, distribution name, CLI entry point,
16
+ the `CGELAB_RUN_JULIA` switch and the URLs all move together.
17
+
18
+ ### Added in 0.2, after 0.2.0
19
+
20
+ - Large-country trade. `ModelSpec.export_demand` puts exports on a demand curve,
21
+ `E / E0 = (pWe / export_price)^(-η)`, and `ModelSpec.import_supply` puts
22
+ imports on a supply curve, `M / M0 = (pWm / world_price)^ψ`: the equations of
23
+ Hosoe's `lrgcge`. A scalar or a mapping by commodity; the rest stay price
24
+ takers. The scenario prices become the shifts of the curves, and
25
+ `PeriodResult.world_export_price` and `world_import_price` hold the solved
26
+ world prices. The base year is unchanged. `export_demand` needs
27
+ `export_rule="cet"`; the regional slice refuses both. The JuMP replica carries
28
+ the curves as constraints, and three new round-trip cases match it to 1e-12.
29
+ - Import tariff and indirect tax on output, separate from the product tax on
30
+ absorption and inside the prices they fall on, as in Hosoe's `stdcge`.
31
+ `calibrate(..., tariffs=)` or `ModelSpec.tariff_account` sets the base-year
32
+ tariff (Hosoe's `taum`), and the Armington nest is calibrated on the
33
+ tariff-inclusive value of imports. `calibrate(..., output_taxes=)` or
34
+ `ModelSpec.indirect_tax_account` sets the output tax (Hosoe's `tauz` / IDT),
35
+ and the CET splits output at its tax-inclusive value, so exports carry it.
36
+ Government receives both as levels. `Scenario.tariff` and
37
+ `Scenario.output_tax` move one rate without moving the other; a tariff of
38
+ zero abolishes it. At the calibrated rates the base year is the SAM. The
39
+ JuMP replica carries the same prices.
40
+ - `Closure(government="saving_rate")`: government saves the base-year share
41
+ of its income (`Economy.gov_savrate`) and spends the rest in base-year value
42
+ shares. `Closure(foreign_saving_unit="foreign_currency")`: foreign saving
43
+ fixed in dollars under `foreign="fixed_saving"`. Together they are Hosoe's
44
+ closure.
45
+ - `cgelab.examples.hosoe`: the SAM, functional forms and closure of Hosoe,
46
+ Gasawa and Hashimoto's `stdcge` and, with `large_country=True`, `lrgcge`.
47
+ The tariff abolition of both matches a line-by-line JuMP transcription of the
48
+ GAMS programs (`validation/hosoe.jl`) in all 49 displayed variables, to
49
+ 2.4e-12; `tests/test_hosoe_stdcge.py` checks it against the stored result.
50
+ - The JuMP replica converges from a cold start on an applied SAM. Household
51
+ income, spending and the Armington shares now start at base-year levels
52
+ instead of at 1 and at guesses; factor prices and the exchange rate still start
53
+ displaced, so the Python answer never enters the start.
54
+ - `PeriodResult.domestic_sales` and `p_domestic`: home sales of domestic output
55
+ and their price. `base_year_reproduction` now also checks imports and
56
+ exports against the SAM.
57
+ - Several regions. `ModelSpec.regions` and `sigma_interregional`: a CES across
58
+ regions of origin under the Armington nest. Accounts are `region:local`.
59
+ Factors clear where they are; one national numeraire stays unsolved. A single
60
+ labelled region reproduces the legacy solver, including on the plain toy with
61
+ taxes and intermediates. `examples.regions` is a hand-written two-region SAM.
62
+ Margins, CET, LES, migration, non-default closures, `run_path` and `to_jump`
63
+ are refused by name on this slice.
64
+ - `factor_demand_by_activity`, `real_gdp` and `sectoral_path`: employment by
65
+ activity, real GDP from both sides with the tax gap named, and a tidy sectoral
66
+ panel along a path. `PeriodResult.factor_demand_by_activity` holds the matrix
67
+ the solver used.
68
+ - A replications page on the site (`site/replications.html`, and the Portuguese pair).
69
+ The benchmark of Hosoe, Gasawa and Hashimoto (2004), chapter 5, as printed in the
70
+ GAMS library file `splcge`, reproduces: output 15 and 35, prices 1. A SAM that
71
+ invests nothing no longer raises on an empty investment basket.
72
+ - `Scenario.investment_mix`: commodity composition of the investment budget.
73
+ Absent, the base-year mix. Distinct from `Growth.allocation`, which shares
74
+ investment across capital stocks.
75
+ - `Closure.labour`: `full_employment` (unchanged default), `fixed_real_wage`,
76
+ `wage_curve` and `elastic_supply`. The three new closures refuse a labour
77
+ numeraire. Unemployment is not paid. `PeriodResult.employment`,
78
+ `unemployment` and `real_wage`. The JuMP export carries the same equations.
79
+
80
+ ### Added in 0.3
81
+
82
+ - SAM multipliers and input–output analysis (`cgelab.multipliers`):
83
+ `accounting_multipliers` (Pyatt and Round), `fixed_price_multipliers` with
84
+ marginal propensities from income elasticities and an Engel-aggregation check,
85
+ `leontief_multipliers` (activities and commodities endogenous), `linkages`
86
+ (backward from the Leontief inverse, forward from the Ghosh inverse, with
87
+ Rasmussen indices) and `structural_paths` (Defourny and Thorbecke). The
88
+ Leontief inverse reproduces Miller and Blair's two-sector example; the total
89
+ influences of all elementary paths add up to the multiplier (Lantner's
90
+ identity), to 1e-10.
91
+
92
+ - National accounts (`national_accounts`): GDP at current prices by expenditure
93
+ and by income, which agree in every equilibrium, and GNI. Price and quantity
94
+ indices (`price_indices`): Laspeyres, Paasche and Fisher by component of final
95
+ demand, for GDP and for the terms of trade, against the base year or another
96
+ solved period. The government account (`government_account`,
97
+ `PeriodResult.government`): revenue by instrument, outlays and saving, recorded
98
+ by the solver at the solution. `PeriodResult.household_saving` and
99
+ `forced_saving`.
100
+
101
+ - Systematic sensitivity (`sensitivity`, `spec_sweep`): Stroud's degree-3
102
+ quadrature, exact in the mean for results up to cubic in the parameters, and
103
+ Monte Carlo with a fixed seed, over `Uniform`, `Normal` and `Triangular`
104
+ parameters. `spec_sweep` recalibrates at every point.
105
+
106
+ - Subtotals (`subtotals`, `path_decomposition`): the Harrison, Horridge and
107
+ Pearson decomposition of a result by groups of shocks, integrated along the
108
+ straight path from reference to alternative. The contributions add up to the
109
+ solved change, with a residual of order 1e-8 that is reported. On closed forms
110
+ they are the line integrals.
111
+
112
+ - Welfare decomposition (`welfare_decomposition`): Huff and Hertel's split of
113
+ the change in real absorption into endowment, technology, one allocative term
114
+ per instrument, terms of trade and the external account, integrated along the
115
+ path. The identity closes to below 1e-9 in ten economies and closures; it is
116
+ not validated against GTAP, which needs the GTAP database.
117
+ - `cgelab.examples.hosoe.build_simple()`: Hosoe's chapter 5 (`splcge`).
118
+
119
+ ### Fixed in 0.3
120
+
121
+ - An undetermined exchange rate is refused. With fixed export shares, a
122
+ Cobb–Douglas Armington on every imported commodity and foreign saving fixed in
123
+ numeraire units, every exchange rate is an equilibrium; the solver used to
124
+ return whichever its start point was.
125
+
126
+ - The activity tax paid by an own-account activity never reached government:
127
+ households paid it in the price and the tax block counted market activities
128
+ only, so the base year did not reproduce and Walras was off by the tax. The
129
+ JuMP replica had the same omission.
130
+
131
+ ### Added in 0.4
132
+
133
+ - Government targets (`Closure.government_target`, `government_adjusts`):
134
+ government saving held fixed (a deficit target) or total revenue held fixed
135
+ (revenue-neutral tax replacement), met by scaling every direct tax rate, every
136
+ product tax rate, or government consumption in base-year shares.
137
+ `PeriodResult.tax_scale` is the factor. The JuMP replica carries the same
138
+ closures; `Economy.gov_saving0` and `gov_revenue0` are the base-year targets.
139
+
140
+ - Emissions accounts (`add_emissions`, `emissions`) calibrated from base-year
141
+ totals by source (combustion in production, household and government fuel
142
+ use, process), and a carbon price (`Scenario.carbon_price`): a tax per unit of
143
+ output by emission intensity on activities, a specific tax on household fuel.
144
+ The revenue is reported by source and recycled by the revenue-neutral
145
+ closure. GDP, the welfare decomposition, subtotals and the JuMP replica carry
146
+ it.
147
+
148
+ - Value-added-energy nesting (`ModelSpec.energy`, `sigma_vae`,
149
+ `sigma_energy`): an energy bundle, a CES across fuels, substitutes for value
150
+ added in a CES; other intermediates stay Leontief. The carbon price on a fuel
151
+ enters the price each activity pays for it. With zero elasticities the nest is
152
+ the Leontief model exactly; with positive ones the fuel ratios meet the CES
153
+ first-order conditions. The JuMP replica carries the nest.
154
+ `PeriodResult.input_coefficients` and `value_added_per_unit` are the
155
+ coefficients the equilibrium used.
156
+
157
+ - GTAP-E's arrangement (`ModelSpec.energy_nest="capital"`, `energy_capital`,
158
+ `sigma_ke`): energy joins a capital factor in a capital-energy composite that
159
+ sits inside the value-added nest. With `sigma_ke = sigma_va` it collapses to the
160
+ value-added nest with `sigma_vae = sigma_va`, and the two solve to the same
161
+ equilibrium to 1e-11; capital and energy meet their first-order condition; the
162
+ JuMP replica carries both arrangements.
163
+ - The bridge to dsgelab (`cgelab.bridge`, `pip install "cgelab[dsge]"`): a
164
+ Ramsey CGE in which an Euler equation chooses investment and every period is
165
+ the SAM model. dsgelab gives its steady state, first-order solution, impulse
166
+ responses and perfect-foresight transitions; `announced` turns a sequence of
167
+ scenarios into an announced policy. In a one-good closed economy it is the
168
+ stochastic growth model: same steady state, transition matrices and path, to
169
+ 1e-7. `toy.build_one_good()` is that economy; `Scenario.investment_level`
170
+ sets real investment under `fixed_real`.
171
+
172
+ - Physical units (`add_physical_units`, `physical`, `physical_coefficient`):
173
+ physical content per unit of a commodity's Armington composite and of an
174
+ activity's output, calibrated from base-year totals; physical supply, use by
175
+ agent, output and intensity of a solved period; and the translation of a
176
+ physical technical coefficient into a SAM entry. Supply meets use in every
177
+ equilibrium, margins included.
178
+
179
+ ### Fixed in 0.4
180
+
181
+ - `homogeneity_test` held a fixed exchange rate at one while it scaled the
182
+ numeraire, so every `foreign="fixed_rate"` closure failed the test for a
183
+ reason that was the test's. The rate is nominal and now scales too.
184
+
185
+ ### Added toward 0.7
186
+
187
+ - `read_har` and `write_har`: GEMPACK header array files, the format of the GTAP
188
+ database, without GEMPACK. On GTAP 10A (2014) the 86 headers harpy3 reads
189
+ agree with it exactly, and four GTAP identities close to single precision.
190
+ The data are licensed and never committed.
191
+
192
+ ### Release engineering (0.5)
193
+
194
+ - CI runs the suite on Python 3.11–3.14 on Linux, macOS and Windows, and against
195
+ the installed wheel (`CGELAB_TEST_INSTALLED=1`), with `twine check`, both with
196
+ dsgelab installed so the bridge is tested. A
197
+ `validation` workflow runs the JuMP replica and the Hosoe transcription on
198
+ demand and weekly. A `release` workflow, started by pushing a tag `vX.Y.Z`,
199
+ checks that the tag matches the version in `pyproject.toml`, the package and
200
+ `CITATION.cff`, and that the dsgelab the `dsge` extra needs is on PyPI;
201
+ publishes to TestPyPI by trusted publishing, installs what TestPyPI serves and
202
+ runs the suite against it, and only then publishes to PyPI. The site's deploy
203
+ is skipped while the repository is private.
204
+ - The sdist carries what its test suite needs (`MANIFEST.in`): the fixtures, the
205
+ site and the tool that runs its examples. `cgelab --version` and
206
+ `python -m cgelab`. The README's links are absolute, so they also work on PyPI.
207
+ - `py.typed`; Python-version, OS and typing classifiers; the `dsge` extra, which
208
+ needs `dsgelab>=0.5`. The licence is declared as an SPDX expression (`MIT`),
209
+ with `LICENSE` as the licence file.
210
+ - The examples, the docs and the site import the package as `cge` and dsgelab as
211
+ `dsg`, and link to dsgelab's site. The site's language selector names both
212
+ languages with an icon.
213
+ - `CONTRIBUTING.md` with the definition of done and a release checklist; issue
214
+ and pull request templates; a known-limitations section in the README.
215
+ - `docs/comparison.md` in English; the Portuguese version is
216
+ `docs/comparison.pt-br.md`.
217
+
218
+ ## 0.2.0 — 2026-09-25
219
+
220
+ The first release as a standalone package. Four gaps and two bugs, found while building a
221
+ regional recursive-dynamic CGE on the package, are closed. Every new `Economy` field defaults to
222
+ zero, so a SAM without the new flows gives the same results as 0.1.0.
223
+
224
+ ### Fixed
225
+
226
+ - **CET exports were never solved.** `export_rule="cet"` was accepted by `ModelSpec` and
227
+ advertised, but the solver always used fixed export shares. Output now splits along the CET
228
+ frontier; the domestic price comes from the inverse revenue function (`cet_domestic_price`).
229
+ - **The external target was read from two fields.** Under `foreign="fixed_saving"` the trade
230
+ target came from `trade_balance0` and saving from `foreign_sav`, so moving `foreign_sav` alone
231
+ left a Walras residual that grew along a path. `foreign_sav` is now the single target.
232
+ - **Institutional flows in the SAM were dropped.** Household income was read as the row total, but
233
+ the solver modelled only factor income: a SAM with a direct tax, a government transfer or a
234
+ remittance missed its own base year (by 12% on `toy.build_with_institutions`).
235
+ - **LES marginal budget shares** assumed commodity spending equals income net of saving, which is
236
+ wrong with direct taxes or purchases made straight from an activity. They now use the calibrated
237
+ commodity budget (`Economy.hh_spend0`).
238
+
239
+ ### Added
240
+
241
+ - `Scenario.export_price` — world export prices, read under CET and refused under fixed shares.
242
+ `sigma_cet` accepts a mapping by commodity.
243
+ - Direct taxes (`gov <- hh`), government transfers (`hh <- gov`) and remittances (`hh <-> row`),
244
+ with saving out of disposable income. `PeriodResult.hh_direct_tax`; welfare income is net of
245
+ direct tax.
246
+ - Factor income paid to government and abroad (`gov <- f`, `row <- f`); foreign saving is the
247
+ current account. `Scenario.foreign_factor_share` overrides the SAM's foreign shares.
248
+ - `Scenario.fdi` — foreign direct investment that raises foreign saving and, in `run_path`, adds
249
+ the capital it buys to a foreign-owned stock whose returns leave the economy.
250
+ `PathResult.foreign_capital` records it.
251
+ - Several capital stocks: `Growth.capital_factor` takes a sequence, `depreciation` a mapping, and
252
+ `allocation` shares domestic investment proportionally or by relative rent.
253
+ - `run_path(economy=f(year, t))` — a different `Economy` each year, for changes that are not
254
+ scenario fields (input coefficients, a foreign-saving path).
255
+ - `econ.diagnostics["unmodelled_flows"]` lists SAM cells the model does not read.
256
+ - The JuMP export replicates all of the above; `validation/roundtrip_jump.py` runs 16 cases
257
+ against Ipopt (worst deviation 3e-12). Opt-in pytest cases with `CGELAB_RUN_JULIA=1`.
258
+ - `toy.build_with_institutions` and `toy.build_with_specific_capital`.
259
+ - A `LICENSE` file, continuous integration, a published site, and the comparison with other
260
+ packages as `docs/comparison.md`.
261
+
262
+ ## 0.1.0 — 2026-09-09
263
+
264
+ First version, developed inside a research repository: SAM container, balance gate and
265
+ sign-preserving RAS; calibration with margins, negative value added, LES and own-account
266
+ activities; within-period solution under five closures; scenarios and wedge recycling; recursive
267
+ dynamics; equivalent and compensating variation with composition-immune group aggregation;
268
+ base-year, homogeneity and Walras diagnostics; export to JuMP.
@@ -0,0 +1,24 @@
1
+ cff-version: 1.2.0
2
+ message: "If you use this software in a publication, please cite it as below."
3
+ type: software
4
+ title: "cgelab: a general toolkit for SAM-based computable general equilibrium models in Python"
5
+ abstract: >-
6
+ Social accounting matrix handling and balancing, calibration, configurable nests and closures, CET and Armington trade, direct taxes, transfers and foreign ownership, within-period solution, recursive dynamics with several capital stocks and FDI, and welfare measurement, with base-year reproduction, homogeneity and Walras checks built in and an independent JuMP replica for validation.
7
+ authors:
8
+ - family-names: "Moreira"
9
+ given-names: "Gustavo Hoffmann"
10
+ email: "gustavo@gakusai.net"
11
+ orcid: "https://orcid.org/0000-0003-0827-2521"
12
+ version: "0.5.0"
13
+ date-released: "2026-10-18"
14
+ license: MIT
15
+ # A repository URL is not an archivable reference. Connect the repository to Zenodo, cut a
16
+ # release, and add the DOI below; that is what makes the citation stable.
17
+ repository-code: "https://github.com/GustavoHM/cgelab"
18
+ url: "https://gustavohm.github.io/cgelab/"
19
+ # doi: "10.5281/zenodo.XXXXXXX"
20
+ keywords:
21
+ - "computable general equilibrium"
22
+ - "social accounting matrix"
23
+ - "input-output"
24
+ - "Python"
cgelab-0.5.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Gustavo Hoffmann Moreira
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,9 @@
1
+ # What the sdist needs beyond the package, so that its test suite runs from the
2
+ # unpacked tree: the fixtures, the site whose examples are tested, and the tool
3
+ # that runs them. validation/ needs Julia and stays out.
4
+ include CHANGELOG.md CITATION.cff
5
+ include tests/conftest.py
6
+ recursive-include tests/data *.json
7
+ include tools/check_site_examples.py
8
+ graft site
9
+ global-exclude .DS_Store
cgelab-0.5.0/PKG-INFO ADDED
@@ -0,0 +1,252 @@
1
+ Metadata-Version: 2.4
2
+ Name: cgelab
3
+ Version: 0.5.0
4
+ Summary: General-purpose toolkit for SAM-based computable general equilibrium models: balancing, calibration, closures, CET trade, institutions and foreign ownership, recursive dynamics with several capital stocks, and welfare.
5
+ Author-email: Gustavo Hoffmann Moreira <gustavo@gakusai.net>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://gustavohm.github.io/cgelab/
8
+ Project-URL: Documentation, https://github.com/GustavoHM/cgelab/tree/main/docs
9
+ Project-URL: Repository, https://github.com/GustavoHM/cgelab
10
+ Project-URL: Issues, https://github.com/GustavoHM/cgelab/issues
11
+ Project-URL: Changelog, https://github.com/GustavoHM/cgelab/blob/main/CHANGELOG.md
12
+ Keywords: cge,general equilibrium,social accounting matrix,input-output,armington
13
+ Classifier: Development Status :: 4 - Beta
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3 :: Only
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Programming Language :: Python :: 3.13
19
+ Classifier: Programming Language :: Python :: 3.14
20
+ Classifier: Operating System :: OS Independent
21
+ Classifier: Typing :: Typed
22
+ Classifier: Topic :: Scientific/Engineering
23
+ Classifier: Intended Audience :: Science/Research
24
+ Classifier: Topic :: Scientific/Engineering :: Mathematics
25
+ Requires-Python: >=3.11
26
+ Description-Content-Type: text/markdown
27
+ License-File: LICENSE
28
+ Requires-Dist: numpy>=1.24
29
+ Requires-Dist: scipy>=1.10
30
+ Requires-Dist: pandas>=2.0
31
+ Provides-Extra: parquet
32
+ Requires-Dist: pyarrow>=14; extra == "parquet"
33
+ Provides-Extra: dsge
34
+ Requires-Dist: dsgelab>=0.5; extra == "dsge"
35
+ Provides-Extra: test
36
+ Requires-Dist: pytest>=7; extra == "test"
37
+ Dynamic: license-file
38
+
39
+ # cgelab
40
+
41
+ [![tests](https://github.com/GustavoHM/cgelab/actions/workflows/tests.yml/badge.svg)](https://github.com/GustavoHM/cgelab/actions/workflows/tests.yml)
42
+ [![site](https://img.shields.io/badge/site-gustavohm.github.io%2Fcgelab-2b6cb0)](https://gustavohm.github.io/cgelab/)
43
+ [![license: MIT](https://img.shields.io/badge/license-MIT-blue)](https://github.com/GustavoHM/cgelab/blob/main/LICENSE)
44
+
45
+ A general toolkit for SAM-based computable general equilibrium models in Python.
46
+ You supply a social accounting matrix. The package calibrates a standard nested
47
+ CGE from it, solves each period, runs a recursive-dynamic path and measures
48
+ welfare. The accounting checks that make any of it believable are built in
49
+ rather than left to the user.
50
+
51
+ A model is assembled from three separable objects, and keeping them separable is
52
+ the point:
53
+
54
+ | Object | Says |
55
+ |---|---|
56
+ | `SAM` | what the base year **was** |
57
+ | `ModelSpec` | what is **assumed** about substitution and functional form |
58
+ | `Closure` | which balances are imposed and **who adjusts** |
59
+
60
+ Results can turn on the last two, so both travel with the results instead of
61
+ living in a branch inside a solver.
62
+
63
+ ## Install
64
+
65
+ ```
66
+ pip install cgelab # from PyPI
67
+ pip install "cgelab[parquet]" # adds pyarrow for .parquet SAMs
68
+ pip install "cgelab[dsge]" # adds dsgelab, for forward-looking investment
69
+ pip install "cgelab @ git+https://github.com/GustavoHM/cgelab" # the current main branch
70
+ ```
71
+
72
+ For development:
73
+
74
+ ```
75
+ git clone https://github.com/GustavoHM/cgelab && cd cgelab
76
+ pip install -e ".[test]" && pytest
77
+ ```
78
+
79
+ Requires Python 3.11+, numpy, scipy and pandas. Try it with no data at all:
80
+
81
+ ```
82
+ cgelab # runs the bundled toy economy and prints the diagnostics
83
+ cgelab my_sam.csv --sigma-armington 2.0 --sigma-va 0.5 # the same on your own SAM
84
+ ```
85
+
86
+ ## Quick start
87
+
88
+ The bundled toy economy has every SAM entry written out, so the base year is
89
+ known on paper and this runs as it is:
90
+
91
+ ```python
92
+ import cgelab as cge
93
+ from cgelab.examples import toy
94
+
95
+ sam, econ = toy.build()
96
+ print(cge.report(econ)) # base-year reproduction, Walras, homogeneity
97
+
98
+ base = cge.solve_period(econ)
99
+ shock = cge.solve_period(econ, scenario=cge.Scenario(
100
+ name="tax +50%", product_tax=econ.ptax * 1.5))
101
+ print(shock.summary())
102
+ ```
103
+
104
+ A counterfactual over a horizon, and its welfare incidence:
105
+
106
+ ```python
107
+ growth = cge.Growth(labour=0.005, tfp=0.010, depreciation=0.05, discount=0.05)
108
+ years = range(2021, 2046)
109
+
110
+ W = cge.consumer_wedge(econ, {"c_ind": 0.03})
111
+ ref = cge.run_path(econ, years=years, growth=growth)
112
+ alt = cge.run_path(econ, years=years, growth=growth,
113
+ scenario=lambda y, t: cge.Scenario(consumer_wedge=W,
114
+ wedge_revenue_to="capital")
115
+ if y >= 2026 else cge.Scenario())
116
+
117
+ ev = cge.equivalent_variation(ref, alt)
118
+ print(cge.ev_by_group(ev, {"hh_1": "rich", "hh_2": "poor"}))
119
+ ```
120
+
121
+ With your own data, the first lines change (a `.parquet` SAM needs the `parquet` extra):
122
+
123
+ ```python
124
+ sam = cge.SAM.read("my_sam.parquet") # or SAM.from_long(df) / SAM.from_square(df)
125
+ sam.check_balance() # a hard gate, not a warning
126
+ econ = cge.calibrate(sam, cge.ModelSpec(sigma_armington=2.0, sigma_va=0.5))
127
+ ```
128
+
129
+ ## Model structure
130
+
131
+ * **Production:** Leontief between the intermediate bundle and value added, and
132
+ within the intermediate bundle. A configurable nest (CES, Cobb–Douglas or
133
+ Leontief) combines factors inside value added.
134
+ * **Make:** commodity market shares are fixed at base-year proportions, so
135
+ activity levels follow from commodity output, `X = MSH @ Q`.
136
+ * **Armington:** CES between domestic and imported varieties.
137
+ * **Exports:** fixed shares by default, or a CET frontier that answers to world
138
+ export prices. The default is deliberate: the CET elasticity is the one
139
+ parameter of a standard CGE that input–output sources do not supply.
140
+ * **Households:** Cobb–Douglas or LES over commodities, out of income net of
141
+ direct tax, saving and payments made straight to an activity. Income includes
142
+ government transfers and net transfers from abroad.
143
+ * **Ownership:** factor income is shared among households, government and the
144
+ rest of the world. Returns to foreign-owned capital leave through the current
145
+ account, and foreign saving is the current account, not the trade balance.
146
+ * **Government, investment, foreign:** five closure combinations, each with its
147
+ own adjusting variable (see `Closure`).
148
+ * **Dynamics:** recursive, with one or several capital stocks accumulated from
149
+ their service flows, investment shared by relative rent, FDI that builds
150
+ foreign-owned capital, and an economy that may change year by year.
151
+
152
+ The **numeraire factor's market is deliberately not solved**. It is left to
153
+ Walras' law, so its residual is an independent check on the accounting rather
154
+ than an identity the solver was told to satisfy. It is recorded on every
155
+ period.
156
+
157
+ ## What is in the box
158
+
159
+ | Capability | Entry point |
160
+ |---|---|
161
+ | SAM container, balance gate, sign-preserving RAS; GEMPACK/GTAP header array files | `SAM`, `read_har`, `write_har` |
162
+ | 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` |
163
+ | Within-period equilibrium; investment, government (including deficit and revenue targets), foreign and labour closures | `solve_period`, `Closure` |
164
+ | Trade: Armington, CET, export demand and import supply curves (large country) | `ModelSpec` |
165
+ | 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` |
166
+ | Counterfactuals: taxes, wedges, endowments, ownership, productivity, own-account levels, world prices, FDI, the investment basket | `Scenario` |
167
+ | Recursive dynamics: several capital stocks, investment allocation, foreign-owned capital, a per-year economy | `run_path`, `Growth` |
168
+ | Forward-looking investment (a Ramsey CGE solved by dsgelab) | `cgelab.bridge` |
169
+ | Accounts: GDP from both sides, Laspeyres, Paasche and Fisher indices, terms of trade, the government account | `national_accounts`, `price_indices`, `government_account` |
170
+ | Decompositions: subtotals by shock, Huff-Hertel welfare decomposition | `subtotals`, `welfare_decomposition` |
171
+ | SAM multipliers, linkages, structural path analysis | `accounting_multipliers`, `linkages`, `structural_paths` |
172
+ | Systematic sensitivity: Stroud quadrature and Monte Carlo over elasticities | `sensitivity`, `spec_sweep` |
173
+ | Welfare: EV, CV and composition-immune group aggregation | `cgelab.welfare` |
174
+ | Base-year reproduction, homogeneity, Walras | `cgelab.diagnostics` |
175
+ | The same equilibrium as a JuMP model, for independent validation | `to_jump` |
176
+
177
+ ## Documentation
178
+
179
+ - [Site](https://gustavohm.github.io/cgelab/): an overview with runnable examples, in English and Portuguese, and a replications page
180
+ - [`docs/guide.md`](https://github.com/GustavoHM/cgelab/blob/main/docs/guide.md): the user guide, from SAM to welfare
181
+ - [`docs/api.md`](https://github.com/GustavoHM/cgelab/blob/main/docs/api.md): API reference
182
+ - [`docs/whitepaper.md`](https://github.com/GustavoHM/cgelab/blob/main/docs/whitepaper.md): the mathematics of calibration, the period equilibrium, recursive dynamics and welfare (in Portuguese)
183
+ - [`docs/design-notes.md`](https://github.com/GustavoHM/cgelab/blob/main/docs/design-notes.md): the accounting decisions and the errors they prevent
184
+ - [`docs/from-scripts.md`](https://github.com/GustavoHM/cgelab/blob/main/docs/from-scripts.md): porting an existing CGE pipeline
185
+ - [`docs/comparison.md`](https://github.com/GustavoHM/cgelab/blob/main/docs/comparison.md): how this package compares with what exists, and where it does not win
186
+ - [`CHANGELOG.md`](https://github.com/GustavoHM/cgelab/blob/main/CHANGELOG.md), [`ROADMAP.md`](https://github.com/GustavoHM/cgelab/blob/main/ROADMAP.md), [`CONTRIBUTING.md`](https://github.com/GustavoHM/cgelab/blob/main/CONTRIBUTING.md)
187
+
188
+ ## Verification
189
+
190
+ Every number the package produces is checked against something it did not
191
+ compute itself:
192
+
193
+ - **Hand-built SAMs** whose every entry is written out, so the base year is known on
194
+ paper: base-year reproduction, zero-degree homogeneity and Walras' law in every
195
+ closure, on every variant (margins, own-account activities, institutions, trade
196
+ taxes, CET, energy nests, carbon).
197
+ - **Closed forms and published tables**: Miller and Blair's Leontief inverse, the
198
+ stochastic growth model (for the bridge to dsgelab), Stroud quadrature on cubics,
199
+ CES first-order conditions, and the identities that hold in every equilibrium
200
+ (GDP from both sides, the welfare decomposition, subtotals that add up).
201
+ - **A published model**: the tariff abolition of Hosoe, Gasawa and Hashimoto's
202
+ `stdcge` and `lrgcge` against a line-by-line JuMP transcription of the GAMS
203
+ programs, in all 49 displayed variables, to 2.4e-12.
204
+ - **An independent replica**: `to_jump` writes the same equilibrium as a JuMP model
205
+ in which nothing is nested. `validation/roundtrip_jump.py` runs 34 cases; the
206
+ nested solver and Ipopt agree to 1.2e-11.
207
+
208
+ ```
209
+ pytest # the suite, without external tools
210
+ cd validation && julia --project=. -e 'using Pkg; Pkg.instantiate()' && cd ..
211
+ python validation/roundtrip_jump.py # the JuMP replica
212
+ python validation/replicate_hosoe.py # stdcge and lrgcge
213
+ ```
214
+
215
+ ## Scope and known limitations
216
+
217
+ `cgelab` covers a single-country CGE at applied scale. It does not have the
218
+ maturity of GAMS or GEMPACK, and [`docs/comparison.md`](https://github.com/GustavoHM/cgelab/blob/main/docs/comparison.md) says
219
+ where it stands. Things to know before relying on it:
220
+
221
+ - **Several regions** share one origin nest under the Armington. Factors do not
222
+ migrate, and the regional slice refuses margins, CET, LES, trade taxes, energy
223
+ nests and most closures by name. GTAP-style bilateral trade is 0.7.
224
+ - **No complementarity**: activities cannot switch off, and there are no quotas,
225
+ price floors or capacity limits. That is 0.8.
226
+ - **The solver** uses finite-difference Jacobians on a few unknowns. It is fine up
227
+ to a few hundred accounts; each commodity put on a trade curve adds an unknown.
228
+ - **Fixed proportions everywhere** (`sigma_va = 0` in every activity) can leave
229
+ the model without a solution under full employment of every factor.
230
+ - **Under fixed export shares** with a Cobb-Douglas Armington, the exchange rate is
231
+ not determined, and `solve_period` refuses that combination; near an Armington
232
+ elasticity of one it is badly conditioned.
233
+ - **Forward-looking investment** goes through [dsgelab](https://github.com/GustavoHM/dsgelab)
234
+ (`pip install "cgelab[dsge]"`). `run_path` itself has no forward-looking agent.
235
+ - **GTAP data** can be read, but not yet aggregated or turned into a SAM, and the
236
+ welfare decomposition has not been compared with GTAP's own.
237
+ - **Platforms**: an editable install (`pip install -e`) can break silently on
238
+ Python 3.14 on macOS; install from the wheel if `import cgelab` fails.
239
+
240
+ ## Citing
241
+
242
+ If a published result went through this package, cite it. Software is a
243
+ methodological input like any other, and the version matters: a number that
244
+ only reproduces under one version is not reproducible without it.
245
+ [`CITATION.cff`](https://github.com/GustavoHM/cgelab/blob/main/CITATION.cff) carries the metadata, with the author's ORCID, in
246
+ the format GitHub reads. A repository URL is not an archivable reference: each
247
+ release will be archived on Zenodo, and the DOI it receives, which will be added
248
+ to that file, is the reference to cite.
249
+
250
+ ## License
251
+
252
+ MIT. See [`LICENSE`](https://github.com/GustavoHM/cgelab/blob/main/LICENSE).