Skip to contents

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

library(multimod)
model_info <- read_gams("my_model.gms")
class(model_info) # "model_structure"
#> [1] "model"    "multimod"

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 an equation to LaTeX

as_latex(eq) |> cat()

𝑣𝑂𝑏𝑗𝑒𝑐𝑡𝑖𝑣𝑒=r,y𝗆𝗏𝖳𝗈𝗍𝖺𝗅𝖢𝗈𝗌𝗍r,y𝑣𝑇𝑜𝑡𝑎𝑙𝐶𝑜𝑠𝑡r,y𝗉𝖯𝖾𝗋𝗂𝗈𝖽𝖫𝖾𝗇y𝗉𝖣𝗂𝗌𝖼𝗈𝗎𝗇𝗍𝖥𝖺𝖼𝗍𝗈𝗋r,y \textit{vObjective} = \sum_{{r,y} \in \textsf{mvTotalCost}_{r,y}} {\textit{vTotalCost}_{r,y} \cdot \textsf{pPeriodLen}_{y} \cdot \textsf{pDiscountFactor}_{r,y}}

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)
#> )

Visualize equation tree

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")

License

MIT License