PEP template (Pyomo)

The PEP-1-1 v2.1 port — see the templates overview for context.

PEP index sets for the Pyomo model.

Wraps the calibrated PEPModelState.sets (the single source of truth produced by PEPModelCalibrator) so the Pyomo builder never redefines set members. Adds the one derived set the equations need: I1 = I \ {walras_i} (all commodities except the Walras/redundant-market commodity, default agr) — used by the composite-good market clearing EQ84 (agr is dropped and handled by the WALRAS/LEON slack).

Default pep2 members (from PEPModelState):

H = [hrp, hup, hrr, hur] households F = [firm] firms K = [cap, land] capital types L = [usk, sk] labor types J = [agr, ind, ser, adm] production sectors I = [agr, food, othind, ser, adm] commodities (note: J ≠ I — PEP make matrix) AG = [hrp, hup, hrr, hur, firm, gvt, row] all agents AGNG = AG {gvt} non-government agents AGD = AG {row} domestic agents

class equilibria.templates.pep_pyomo.pep_pyomo_sets.PEPSets(H=<factory>, F=<factory>, K=<factory>, L=<factory>, J=<factory>, I=<factory>, AG=<factory>, AGNG=<factory>, AGD=<factory>, walras_i='agr')[source]

Bases: object

Index sets for the PEP Pyomo model, sourced from a calibrated PEPModelState.

Parameters:
H: list[str]
F: list[str]
K: list[str]
L: list[str]
J: list[str]
I: list[str]
AG: list[str]
AGNG: list[str]
AGD: list[str]
walras_i: str = 'agr'
property I1: list[str]

Commodities except the Walras/redundant-market commodity (EQ84 domain).

classmethod from_state(state)[source]
Parameters:

state (Any)

Return type:

PEPSets

PEP calibrated parameters for the Pyomo model.

Wraps PEPModelState blocks (production/income/trade/consumption/les_parameters/gdp) into one flat, case-preserving lookup so the equation rules read parameters by their GAMS-style names (e.g. P["io","agr"], P["beta_VA","agr"], P["KDO","cap","agr"]).

Benchmark levels end in O (KDO, YHO, IMO, …). CES/share params keep their block names (rho_VA, beta_KD, B_XT, sigma_M, …). Derived params that the cyipopt solver computes in _extract_parameters (gamma_INV, gamma_GVT, sigma_*, eta, kmob) are recomputed here from the same benchmark inputs so the Pyomo model is self-contained.

class equilibria.templates.pep_pyomo.pep_pyomo_parameters.PEPParams(state)[source]

Bases: object

Flat calibrated-parameter accessor over a PEPModelState.

p[name] → scalar or dict; p[name, i] / p[name, i, j] → indexed value. Missing indexed entries return 0.0 (matches the GAMS $-masked default), missing names raise KeyError (a real typo, not a benign zero).

Parameters:

state (Any)

get(name, *idx, default=0.0)[source]
Parameters:
Return type:

Any

names()[source]
Return type:

list[str]

PEP CGE model as a Pyomo ConcreteModel — Vars + all ~96 EQ Constraints.

Faithful port of the cyipopt residual system (pep_model_equations.py). Each residual f(x)=0 becomes a Pyomo Constraint lhs == rhs. Sets/params come from PEPSets/PEPParams (which wrap the calibrated PEPModelState). The $-masks of the GAMS/residual code are resolved at construction from the *O/*O0 benchmark params (an equation instance is built only where its benchmark level is non-zero), matching the cyipopt active-set.

Builder entry point: build_pep_model(state, variant=”base”, form=”nlp”) -> ConcreteModel.

variant: “base” (EQ1..EQ98 + WALRAS) | “objdef” (adds OBJDEF: OBJ==0, free OBJ) form: “nlp” (min 0 over the equality system) | “mcp” (walras⊥LEON, e fixed numeraire)

equilibria.templates.pep_pyomo.pep_pyomo_equations.build_pep_model(state, variant='base', form='nlp')[source]
Parameters:
Return type:

ConcreteModel

PEP equation blocks as Pyomo Constraints — faithful to pep_model_equations.py.

Each EQn residual f=0 becomes lhs == rhs. Equations are instantiated only over their active index sets (the GAMS $-masks, precomputed in idx). Constraints are named eqN (lowercase) with the GAMS index suffix in the Constraint’s own index.

attach_all_blocks(m, S, P, idx, variant) -> int attaches every block, returns the count.

equilibria.templates.pep_pyomo.pep_pyomo_blocks.attach_all_blocks(m, S, P, idx, variant)[source]
Return type:

int

Counterfactual scenarios for the PEP model — the ** 6.4 Simulations block of PEP-1-1_v2_1.gms, applied to the CALIBRATED STATE before build_pep_model.

GAMS applies a scenario by fixing a benchmark-derived rate (e.g. ttix.fx(i)=ttixO(i)*0.75) right before the solve. Since the Pyomo port derives every model rate from the calibrated state’s *O benchmarks (PEPParams reads state.trade[‘ttixO’] etc.), the faithful analog is to scale that benchmark IN THE STATE, then build — the model then carries the shocked rate everywhere GAMS’s fixed variable would. This keeps the builder scenario-agnostic (the scenario is external, exactly as in the .gms).

SIM1 (the one uncommented simulation in the reference .gms): a 25% cut to the export-tax rate — ttix.fx(i) = ttixO(i)*0.75. (The comment says “all indirect tax rates” but only the ttix line is active; GAMS is the source of truth, so only ttix is scaled.)

equilibria.templates.pep_pyomo.pep_pyomo_scenarios.apply_sim1_export_tax_cut(state, factor=0.75)[source]

Scale the export-tax benchmark ttixO in-place by factor (default 0.75 = −25%, the reference SIM1). Mutates and returns state so PEPParams derives the shocked ttix. Idempotent only per fresh calibration — call on a newly calibrated state, not twice.

Parameters:
Return type:

Any

Solve the PEP Pyomo model and read variable values out.

NLP form: IPOPT on the raw model with nlp_scaling_method=none (faithful to GAMS, which solves the raw model; the GTAP saga proved Pyomo’s default gradient pre-scaling steers IPOPT to a wrong basin — see project_gtap7_altertax_ref_and_nlp_scaling).

MCP form: PATH via path-capi-python (walras⊥LEON free-row, e fixed numeraire), mirroring the GTAP MCP path. Falls back to a clear error if PATH is unavailable.

The benchmark BASE reproduces the SAM, so seeding at *O levels and solving should return residual≈0 (the cyipopt solver early-exits there) — that is the parity anchor.

class equilibria.templates.pep_pyomo.pep_pyomo_solver.PEPSolveResult(code: 'int', max_residual: 'float', values: 'dict[str, Any]'=<factory>, message: 'str' = '')[source]

Bases: object

Parameters:
code: int
max_residual: float
values: dict[str, Any]
message: str = ''
equilibria.templates.pep_pyomo.pep_pyomo_solver.solve_pep(m, tol=1e-07, max_iter=3000)[source]

Solve the built PEP model. NLP forms go through IPOPT (raw, no pre-scaling).

Parameters:
Return type:

PEPSolveResult