gdxtools reads and writes GDX files (the GAMS database exchange format) from R, exposing parameters, sets, variables and equations as plain data.frames with domain columns + a value column. From v1.0.0 onward the package is backed by gamstransfer, the GDX I/O package maintained by GAMS Software GmbH. No compiled code ships with gdxtools.
Installation
if (!requireNamespace("remotes")) install.packages("remotes") remotes::install_github("lolow/gdxtools")
gamstransfer (CRAN) is the only required dependency. A working GAMS installation is needed only if you call gams() to run a .gms file.
Reading a GDX
library(gdxtools) mygdx <- gdx("results.gdx") print(mygdx) # <results.gdx, 8 symbols> print(mygdx$parameters$name) # parameters available all_items(mygdx) # lists of names by symbol type # Parameter — returns a data.frame with domain columns + value travel_cost <- mygdx["travel_cost"] # Variable / equation fields: "l" (level, default), "m" (marginal), # "lo" (lower bound), "up" (upper bound) lo_travel_time <- mygdx["travel_time", field = "lo"] m_time_constraint <- mygdx["time_constraint", field = "m"] # Extract the same item from several GDX files allparam <- batch_extract("myparam", files = c("test1.gdx", "test2.gdx"))
Writing a GDX
# Parameters param1 <- data.frame(x = c("1","2","4","8"), value = 1:4) attributes(param1) <- c(attributes(param1), gams = "definition of parameter 1") param2 <- data.frame(a = c("london","paris","tahiti"), value = c(50, 0.2, 1e-2)) write.gdx("test.gdx", params = list(param1 = param1, param2 = param2)) # Sets — pass each one as a data.frame; column names become its dimensions myset1 <- data.frame(a = c("london","paris","tahiti")) myset2 <- data.frame(a = c("london","paris","tahiti"), b = c("tahiti","tahiti","paris")) write.gdx("test1.gdx", sets = list(city = myset1, road = myset2)) # Variables — give level / lower / upper as separate named lists; missing # entries fall back to free-var defaults (level 0, lower -Inf, upper +Inf) var_l <- data.frame(a = c("london","paris","tahiti"), value = 0.2) var_lo <- data.frame(a = c("london","paris","tahiti"), value = 1e-2) var_up <- data.frame(a = c("london","paris","tahiti"), value = 50) write.gdx("test2.gdx", vars_l = list(travel_time = var_l), vars_lo = list(travel_time = var_lo), vars_up = list(travel_time = var_up)) # Compressed output write.gdx("test.gdx", params = list(param1 = param1), compress = TRUE) # write2.gdx — alias of write.gdx for params + sets only (kept for # backward compatibility; both use the same fast path) write2.gdx("test.gdx", params = list(param1 = param1, param2 = param2))
Policies for NA values and duplicate keys
write.gdx() exposes two policy arguments that default to the legacy v0.7 semantics so existing code keeps producing bit-identical output. Opt in when you want the alternate behaviour:
# NA / NaN values in parameter `value` columns write.gdx("out.gdx", params = list(p = p), na = "drop") # default: silently drop write.gdx("out.gdx", params = list(p = p), na = "keep") # preserve as GAMS NA write.gdx("out.gdx", params = list(p = p), na = "error") # stop on any NA # Duplicate index keys write.gdx("out.gdx", params = list(p = p), dup = "first") # default: keep first write.gdx("out.gdx", params = list(p = p), dup = "last") # keep last (GAMS-process semantic) write.gdx("out.gdx", params = list(p = p), dup = "error") # stop on duplicates
A warning fires when rows are actually dropped so the count is always audible.
Migrating from 0.7.x
| 0.7 call | 1.0 equivalent |
|---|---|
write.gdx(..., removeLST = FALSE, usetempdir = FALSE) |
arguments accepted but ignored (no .gms/.lst) |
write.gdx(..., digits = 16) |
accepted but ignored (full double precision) |
rgdx, wgdx, gdxInfo, rgdx.param, rgdx.set, rgdx.scalar (low-level gdxrrw) |
removed — use gamstransfer::Container directly |
igdx(), gams() |
kept as thin shims (PATH-based GAMS discovery + system2 runner) |
A sparse parameter no longer densifies on read: only entries actually stored in the GDX come back. Variables and equations are unaffected.
See NEWS.md for the complete list of behaviour changes and bug fixes in 1.0.0.