GEModelR interprets GEMPACK-style TABLO models in R and solves them through the
established GEModel workflow.
This package derives from the public
mivanic/tabloToR repository at audited
commit
7e063c65a19713857ed13023f8b77dad45b15c90.
Maros Ivanic authored that upstream baseline and David Zenz authored the
reviewed post-baseline sparse and native solver work. The upstream baseline has
an accepted public-domain/CC0 basis; it is credited here even though CC0 does
not require attribution.
The current package identity is GEModelR, licensed under GPL-3.0-or-later
(GPL (>= 3) in R package metadata). Maros Ivanic authored the upstream
baseline; David Zenz authored the reviewed post-baseline sparse and native
solver work. Dependency compatibility and the upstream Git alias have been
reviewed. Public release remains pending exact artifact qualification and
publication; the license decision alone does not publish a release.
Migrate from tabloToR for exact library, namespace,
dependency, renv, runtime-option, installation, and saved-state instructions.
GEModelR is an immediate replacement and does not provide a compatibility shim.
Version 0.1.0 currently remains a development candidate. The proposed Git
release and R-universe channel below are pending publication and have not been
verified as available for this candidate.
From an existing local GEModelR checkout with its declared dependencies installed:
R CMD INSTALL .
After the approved v0.1.0 release is actually published, the proposed Git
installation is pinned to that tag:
git clone --branch v0.1.0 --depth 1 https://github.com/DavidZenz/GEModelR.git GEModelR
R CMD INSTALL GEModelR
Use a supported R/Matrix installation and satisfy the dependencies in
DESCRIPTION before R CMD INSTALL. The proposed R-universe installation uses
CRAN as the dependency fallback:
install.packages(
"GEModelR",
repos = c(
GEModelR = "https://davidzenz.r-universe.dev",
CRAN = "https://cloud.r-project.org"
)
)
These are proposed instructions, not a claim that either public installation
has passed. Follow the migration guide for predecessor namespaces,
options, and saved states. Start with the redistributable
first-simulation guide, which uses
GEModelR::GEModel$new() and requires no external GTAP inputs. The default engine
remains legacy; the sparse engine and its Matrix backend are selected explicitly
in that example. Optional native backends depend on installed-build capabilities.
Matrix support: 1.6-5 through 1.7-6. Matrix 1.6-5 passed source
installation and the installed solver contract on all five oldrel-1
platform/build pairings. On release R 4.6.1 and devel R 4.7.0, its source
failed on macOS serial and Windows serial/OpenMP; those six tuples are
excluded. The Linux minimum tuples and current endpoint tuples passed. Support
does not promise that every R/Matrix/platform combination can install. The
minimum will advance only after the next oldest supported R window has a
compatible Matrix source release that passes the same installed solver
contract. Full package checks and remaining release qualification are tracked
separately; these solver results do not resolve the outstanding release
blockers.
model = GEModelR::GEModel$new()
# You need to have the model, such as gtap.tab
model$loadTablo('gtap.tab')
# You need to get the data files .har
data = list(
# The file with GTAP sets may alternatively be called sets.har by some data aggregation programs
gtapsets = HARr::read_har('gsdgset.har'),
# The file with GTAP parameters may alternatively be called default.prm by some data aggregation programs
gtapparm = HARr::read_har('gsdgpar.har'),
# The file with GTAPdata may alternatively be called basedata.har by some data aggregation programs
gtapdata = HARr::read_har('gsdgdat.har')
)
# Initialize the model object
model$loadData(data)
# Set up the closure
for(var in c("afall",
"afcom",
"afeall",
"afecom",
"afereg",
"afesec",
"afreg",
"afsec",
"ams",
"aoall",
"aoreg",
"aosec",
"atall",
"atd",
"atf",
"atm",
"ats",
"au",
"avaall",
"avareg",
"avasec",
"cgdslack",
"dpgov",
"dppriv",
"dpsave",
"endwslack",
"incomeslack",
"pfactwld",
"pop",
"profitslack",
"psaveslack",
"tf",
"tfd",
"tfm",
"tgd",
"tgm",
"tm",
"tms",
"to",
"tpd",
"tpm",
"tp",
"tradslack",
"tx",
"txs")){
model$variableValues[[var]][]=0
}
model$variableValues$qo[model$data$endw_comm,] = 0
# Specify sets for shocks
ag= c("grains", "v_f", "osd", "c_b", "pfb", "ocr", "ctl", "oap", "rmk", "wol")
model$variableValues$aoall[ag,c("northam")] = 1
agFood = c("grains", "v_f", "osd", "c_b", "pfb", "ocr", "ctl", "oap", "rmk", "wol", "food")
model$variableValues$tms[agFood,,c("northam")] = (model$data$viws[agFood,,c("northam")] / model$data$vims[agFood,,c("northam")] -1)*100
# Run the model
model$solveModel(iter = 3,steps = c(1,3))
# View the results (variable ev--welfare)
model$data$ev
The legacy solver remains the default. For large, unaggregated GTAP runs, opt into the integer-indexed sparse engine after loading the TABLO recipe and HAR data:
model <- GEModelR::GEModel$new()
model$loadTablo("gtapv7.tab")
model$setClosure(c("tm", "tms", "qo", "pop"))
model$loadData(
list(
gtapsets = HARr::read_har("sets.har"),
gtapdata = HARr::read_har("basedata.har"),
gtapparm = HARr::read_har("default.prm")
),
engine = "sparse"
)
# Only nonzero shocks need to be stored.
model$setShocks(setNames(
c(1.5),
'tms["eu27","uk"]'
))
print(model$estimateMemory(engine = "sparse"))
model$solveModel(
iter = 3,
steps = c(1, 3),
engine = "sparse",
postsim = FALSE,
output = "compact",
variables = c("ev", "qo"),
diagnostics = TRUE
)
model$compactOutput
Use model$setMemoryBudget(bytes) or memory_budget = bytes to make the solver fail during preflight when the estimate exceeds the available budget. setClosure() accepts base variable names; indexed labels belong in setShocks(). Existing variableValues initialization remains supported when setShocks() is omitted.
The sparse path uses Matrix sparse LU with fill-reducing ordering by default. SuiteSparse remains a recognized backend ID but is unavailable in supported installed builds pending portable support. An explicit SuiteSparse request fails capability preflight before matrix emission or runtime compilation. Explicitly select backend = "Matrix" for a supported sparse solve:
model$solveModel(engine = "sparse", backend = "Matrix")
Installing system SuiteSparse libraries or setting its reserved ordering option does not enable this backend. SparseM remains available as backend = "SparseM" for comparison. DuckDB is intentionally not a solver dependency: it may be useful for staging or aggregating HAR-derived data, but the indexed equation compiler still requires direct numeric access to the model arrays.
For the unaggregated GTAP layout, the opt-in StructuredSchur backend performs exact staged elimination of the local production, bilateral, and (when nonsingular) endowment blocks, then solves the remaining sparse system in block-triangular form. Singular local blocks are retained in the reduced system and reconstructed exactly after solving:
model$solveModel(
engine = "sparse",
backend = "StructuredSchur",
iter = 3,
steps = c(1, 3),
diagnostics = TRUE
)
Its native elimination helper is compiled during package installation, so solves do not invoke a compiler at runtime. The backend keeps the reduced system sparse, and refuses to apply a result whose true residual exceeds the configured tolerance. It is intentionally opt-in and recognizes the GTAP family layout; other TABLO models should explicitly select Matrix or SparseM.
When the remaining BTF block is numerically difficult, use the matrix-free regional Schur backend:
model$solveModel(engine = "sparse", backend = "StructuredSchurFGMRES", iter = 1, steps = 1, diagnostics = TRUE)
It eliminates commodity blocks exactly, preconditions the external system with condensed regional blocks and the global arrowhead, and verifies the true residual. The default structured residual guard is 2e-7 for the ill-conditioned full GTAP system; set options(GEModelR.sparse.structured_residual_tolerance = 1e-7, GEModelR.sparse.schur_tolerance = 1e-7) for a stricter check. Tune GEModelR.sparse.schur_region_batch_size, GEModelR.sparse.schur_panel_size, GEModelR.sparse.schur_restart, GEModelR.sparse.schur_max_iterations, and GEModelR.sparse.schur_refinement_iterations only after checking convergence diagnostics.
The C++ acceleration remains opt-in while the R implementation is the correctness reference. It preserves the exact matrix-free operator and uses native sparse triangular solves, fused Schur accumulation, and LAPACK only for dense regional and global factors:
options(GEModelR.sparse.schur_cpp_threads = 4L)
model$solveModel(
engine = "sparse",
backend = "StructuredSchurFGMRESCpp",
iter = 3,
steps = c(1, 3),
diagnostics = TRUE
)
The native backend performs a registered-symbol, ABI, Matrix-factor, and thread-capability check before constructing the coefficient matrix. An unavailable or incompatible native backend fails clearly and never substitutes the R solver. The option defaults to 1L; request more than one thread only when diagnostics report openmp_compiled = TRUE. Existing C++ shock and thread-scaling observations are diagnostic measurements; they do not guarantee package-wide or end-to-end GTAP speedups. A current matched full-scale R/C++ comparison and independent review remain unqualified for this candidate.
For reproducible A/B measurements, use benchmarks/run_gtap12a_ab.R. It launches fresh R processes, validates input/configuration signatures, compares solutions and residuals, and exits nonzero when a numerical, memory, or performance gate fails.
For a separate-process GTAP 12a measurement, install the package and run:
Rscript benchmarks/benchmark_gtap12a.R \
--data-dir="/path/to/gtap12a" \
--tablo="/path/to/gtapv7.tab" \
--closure-file="/path/to/closure.rds" \
--backend=StructuredSchurFGMRESCpp \
--threads=4 \
--panel-size=64 \
--steps="1,3"
The harness records HAR load, compilation, sparse construction/factor-solve timings, estimated triplets, peak resident memory, physical RAM, and whether a dense fallback was used.
Exact source-archive qualification and installed serialization under a supported R/Matrix runtime remain unverified for this candidate, and current hosted Windows provenance evidence is unavailable. Benchmark component improvements and isolated reuse prototypes must be reported separately from whole-model measurements. The external benchmark preflight also has known report-redaction and reference-file binding limitations; its eligibility report alone is not publication-grade correctness evidence. Private model inputs, full solutions, and raw measurements are not part of the proposed public source distribution.
The canonical GEModelR repository is a
separate publication target. Its first source snapshot and release are pending;
the issue tracker is available.
The documentation address remains a planned destination until the site is
published. Use the bundled guides locally with
browseVignettes("GEModelR") or read MIGRATION.md in this checkout.
Until Pages is deployed, DESCRIPTION advertises the live repository URL and
records documentation status as pending. The planned site stays configured;
its URL will enter package metadata when deployment and URL checks succeed.
After the first publication on main, the complete migration reference will be
at https://github.com/DavidZenz/GEModelR/blob/main/MIGRATION.md.
Development keeps its existing repository and full history. Publication uses a separate, allowlisted source snapshot with no development-history parents; creating the empty publication repository does not itself publish that snapshot.
Evidence-Key: R/GEModel.R::GEModel$loadTablo Evidence-Key: R/GEModel.R::GEModel$solveModel Evidence-Key: R/processTablo.R::processTablo Evidence-Key: R/sparseCompiler.R::sparse_compile_spec Evidence-Key: R/sparseSolver.R::sparse_solve_model Evidence-Key: src/sparse-schur.cpp::GEModelR_schur_accumulate_global
The dependency/native license audit is bundled at Dependency license audit.
The declared R minimum is 3.5.0, matching Matrix's existing dependency floor and the version-3 serialization format already used for saved states. Current platform qualification remains the separately documented native CI matrix.