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

The package is under active development. Contributions, bug reports, and feature requests are welcome! See Get started for an overview of the current functionality and {devstatus} for the roadmap.

Workflow Diagram

Items in curly braces {} are planned for implementation, double curly braces {{}} are potential extensions.

[ GAMS / {JuMP / Pyomo / GMPL} ]
              ↓
          read_gams()
         {read_jump()}
         {read_pyomo()}
         {read_gmpl()}
           {{...}}
              ↓
     ┌────────────────────┐
     │  model_structure   │
     │ (a named list ...) │
     └────────────────────┘
              ↓
        as_multimod()
              ↓
   ┌────────────────────────┐
   │    Core Structures     │      as_visNetwork()
   │    <ast>, <multimod>   │     {as_diagrammer()}
   │ (sets, parameters,     │ ⟷  {{symbolsic manipulation}}
   │  variables, equations, │     {fold_parameters(), ...}
   │  mappings, ...)        │     {data exchange}
   └────────────────────────┘
              ↓
     ┌────────────────────┐
     │ Rendering / Output │
     └────────────────────┘
              ↓
   → write_latex()
   → write_gams()
   → {write_jump()}
   → {write_pyomo()}
   → {write_gmpl()}
   → {{write_ampl()}}
   → {{write_mps()}}
   → {{write_cplex()}}
   → {{write_gurobi()}}
   → {{...}}

Installation and Example Workflow

# install.packages("pak")
pak::pak("optimal2050/multimod")

Load a GAMS model and parse

library(multimod)
model_info <- read_gams("my_model.gms")
class(model_info) # "model_structure"
mod <- as_multimod(model_info, name = "My model in multimod format")
class(mod) # "model"    "multimod"
#> [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]}, *, vTotalCost[region,year], pPeriodLen[year] * pDiscountFactor[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], vTotalCost[region,year] * pPeriodLen[year] * pDiscountFactor[region,year]);
# {as_jump(mod$equations[["eqObjective"]])}

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 GAMS model

write_gams(mod, file = "my_multimod_model.gms")

License

MIT License