The multimod R package is an effort to bridge alternative mathematical modeling frameworks and languages, particularly those used in energy system modeling. It defines a domain-specific language (DSL) for representing mathematical programming models in a unified, abstract format.
multimod supports partial parsing of models written in GAMS (General Algebraic Modeling System), and is being extended to support more GAMS language features, as well as JuMP (Julia), Pyomo (Python), and GMPL (GNU Math Programming Language). Parsed models can be converted into the multimod format for analysis, manipulation, visualization, or rendering to LaTeX and other modeling languages.
The package is designed to facilitate the exchange of mathematical models across different languages and solver frameworks, with the goal of simplifying the development, comparison, and reuse of complex optimization models in energy systems and beyond.
Development Status
WARNING: The package is in active development. All implementations are experimental and APIs may change. See Get started for an overview of current functionality and Development Roadmap for implementation status and future plans.
Workflow Diagram
┌─────────────────────────────┐
│ Input Formats │
├─────────────────────────────┤
│ GAMS (basic/linear only) │ → read_gams()
│ GMPL (limited features) │ → read_gmpl()
│ {JuMP} (planned) │ → {read_jump()}
│ {Pyomo} (planned) │ → {read_pyomo()}
│ {{AMPL, MPS, ...}} │ → {{...}}
└─────────────────────────────┘
↓
┌────────────────────────┐
│ multimod Core │ Analysis & Manipulation:
│ (Abstract Syntax Tree) │ • fold_model() [✓]
├────────────────────────┤ • trim_model() [✓]
│ • Sets & Aliases │ → • save_model() [✓]
│ • Parameters │ • as_visNetwork() [✓]
│ • Variables │ ← • model statistics [✓]
│ • Equations │ {{auto-mapping}} [ ]
│ • Mappings │ {{symbolic simplify}} [ ]
└────────────────────────┘
↓
┌─────────────────────────────────┐
│ Output Formats │
├─────────────────────────────────┤
│ LaTeX (stable) [✓] │ → write_latex()
│ {GMPL} (testing) [~] │ → write_gmpl()
│ {JuMP} (testing) [~] │ → write_jump()
│ {Pyomo} (testing) [~] │ → write_pyomo()
│ {{GAMS}} (planned) [ ] │ → {{write_gams()}}
│ {{AMPL, MPS, LP, ...}} [ ] │ → {{...}}
└─────────────────────────────────┘
Status: [✓] implemented | [~] and { } developing | [ ] and {{ }} considering
Installation and Example Workflow
# install.packages("pak")
pak::pkg_install("optimal2050/multimod")Load a GAMS model and parse
AST elements: an example equation
eq <- mod$equations[["eqObjective"]]
print(eq)
#> <AST equation> eqObjective
#> relation: ==
#> lhs: vObjective
#> rhs: sum(if (mvTotalCost[region,year]) {[region,year]}, *, pDiscountFactorMileStone[region,year], vTotalCost[region,year], FALSE)Render a specific equation to GAMS or Julia/JuMP
as_gams(eq) |> cat()
#> eqObjective..
#> vObjective =e=
#> sum(([region,year])$mvTotalCost[region,year], pDiscountFactorMileStone[region,year] * vTotalCost[region,year]);
as_jump(eq) |> cat()
#> @constraint(
#> model,
#> eqObjective,
#> vObjective == sum(get(pDiscountFactorMileStone, (region, year), pDiscountFactorMileStoneDef) * vTotalCost[region, year] for (region, year) in mvTotalCost)
#> )Write the entire model to LaTeX
write_latex(mod,
file = "my_multimod_model.tex",
title = "My multimod model equations",
subtitle = "Generated by multimod package")
tinytex::pdflatex("my_multimod_model.tex")Write JuMP/Julia model
# Complete workflow: save data and generate JuMP code
save_model(mod, "my_model_dir", format = "ipc") # Arrow format
write_jump(mod, model_dir = "my_model_dir") # Generate Julia code
# Solve with Julia
solve_jump(model_dir = "my_model_dir")Write & solve GMPL model
write_gmpl(mod, model_dir = "my_model_dir")
solve_gmpl(mod, model_dir = "my_model_dir")Write & solve Python/Pyomo model
write_pyomo(mod, model_dir = "my_model_dir")
solve_pyomo(mod, model_dir = "my_model_dir"){Write GAMS model}
# in progress
write_gams(mod, file = "my_multimod_model.gms")