Closures and Accounting Checks
JCGE distinguishes conditions that define the solved equilibrium from identities retained to verify the solution. This keeps a model's complete equation inventory available for reporting while avoiding redundant solver constraints.
Declare roles in the model closure
JCGECore identifies an equation by its block name, tag, and indices. Every condition is solver-enforced by default. Mark only an identity that is implied by the selected closure as an :accounting_check.
using JCGECore
pool_check = ClosureCondition(:investment_pool, :investment_pool_clearing)
closure = ClosureSpec(:P_HH_COMMON;
kind = :price_index,
condition_roles = Dict(pool_check => :accounting_check),
)The key is part of the model specification rather than a solver-specific exception. The corresponding equation remains visible in generated equation listings and can be checked after solution.
Obtain keys from reusable blocks
JCGEBlocks provides closure_condition so that a model can obtain the same key used by a block without repeating its name manually:
using JCGEBlocks
pool_check = closure_condition(pool, :investment_pool_clearing)
market_check = closure_condition(
market, :regional_composite_market, :g1_r1, :r1)The arguments after the tag are the equation indices. The runtime also exposes closure_conditions(ctx) after a model is built, which is useful for inspecting the available keys.
Solve and check residuals
JCGERuntime.run! compiles :enforce conditions into solver constraints, retains :accounting_check conditions outside the solver, and evaluates their residuals after a successful solve:
using JCGERuntime, Ipopt
result = run!(spec; optimizer=Ipopt.Optimizer)
checks = filter(r -> r.role == :accounting_check,
equation_residuals(result.context))For advanced workflows that call solve! directly, call evaluate_residuals!(ctx) before inspecting equation_residuals(ctx).
Report the closure
JCGEOutput can show the role beside every rendered equation and persists post-solution accounting residuals alongside other results:
using JCGEOutput
equations = render_equations(result;
format = :markdown,
show_condition_roles = true,
)
results = collect_results(result)
checks = results.accounting_checksAccounting checks are included in JSON, CSV, Arrow, Parquet, and DualSignals exports. In tidy exports their row type is :accounting_check; in DualSignals their absolute residual is recorded as slack and their dual is zero.