From 64ac10454d4adf0a1da25f3c23391a1ceda445c2 Mon Sep 17 00:00:00 2001 From: Oscar Dowson Date: Fri, 12 Jun 2026 17:05:39 +1200 Subject: [PATCH 1/2] Add JuliaFormatter and update the README --- .JuliaFormatter.toml | 9 + .github/dependabot.yml | 7 + .github/workflows/ci.yml | 29 +-- .github/workflows/format_check.yml | 29 +++ README.md | 64 ++++--- src/GDXFile.jl | 296 +++++++++++++++++++++++------ src/GDXInterface.jl | 18 +- src/gdx_c_api.jl | 160 +++++++++++++--- test/test_gdxfile.jl | 104 ++++++---- 9 files changed, 535 insertions(+), 181 deletions(-) create mode 100644 .JuliaFormatter.toml create mode 100644 .github/dependabot.yml create mode 100644 .github/workflows/format_check.yml diff --git a/.JuliaFormatter.toml b/.JuliaFormatter.toml new file mode 100644 index 0000000..f196f10 --- /dev/null +++ b/.JuliaFormatter.toml @@ -0,0 +1,9 @@ +# Configuration file for JuliaFormatter.jl +# For more information, see: https://domluna.github.io/JuliaFormatter.jl/stable/config/ + +always_for_in = true +always_use_return = true +margin = 80 +remove_extra_newlines = true +separate_kwargs_with_semicolon = true +short_to_long_function_def = true diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..700707c --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,7 @@ +# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates +version: 2 +updates: + - package-ecosystem: "github-actions" + directory: "/" # Location of package manifests + schedule: + interval: "weekly" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ba9a9b5..0d039c1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,9 +1,7 @@ name: CI on: push: - branches: - - main - - release-* + branches: [main] pull_request: types: [opened, synchronize, reopened] # needed to allow julia-actions/cache to delete old caches that it has created @@ -17,29 +15,12 @@ jobs: strategy: fail-fast: false matrix: - # Only test on a subset of possible platforms. - include: - - version: '1' # The latest point-release (Linux) - os: ubuntu-latest - arch: x64 - - version: '1' # The latest point-release (Windows) - os: windows-latest - arch: x64 - - version: '1.10' # 1.10 LTS (64-bit Linux) - os: ubuntu-latest - arch: x64 - - version: '1.10' # 1.10 LTS (64-bit Windows) - os: windows-latest - arch: x64 - - version: '1.10' # 1.10 LTS (64-bit Mac Intel) - os: macos-15-intel - arch: x64 - - version: '1.10' # 1.10 LTS (64-bit Mac Arm) - os: macOS-latest - arch: arm64 + version: ['1.10', '1'] + os: [ubuntu-latest, macOS-latest, windows-latest] + arch: [default] steps: - uses: actions/checkout@v6 - - uses: julia-actions/setup-julia@v2 + - uses: julia-actions/setup-julia@v3 with: version: ${{ matrix.version }} arch: ${{ matrix.arch }} diff --git a/.github/workflows/format_check.yml b/.github/workflows/format_check.yml new file mode 100644 index 0000000..710b1ca --- /dev/null +++ b/.github/workflows/format_check.yml @@ -0,0 +1,29 @@ +name: format-check +on: + push: + branches: + - main + pull_request: + types: [opened, synchronize, reopened] +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: julia-actions/setup-julia@latest + with: + version: '1' + - uses: actions/checkout@v6 + - name: Format check + shell: julia --color=yes {0} + run: | + using Pkg + Pkg.add(PackageSpec(name="JuliaFormatter", version="2")) + using JuliaFormatter + format(".", verbose=true) + out = String(read(Cmd(`git diff`))) + if isempty(out) + exit(0) + end + @error "Some files have not been formatted !!!" + write(stdout, out) + exit(1) diff --git a/README.md b/README.md index 4694cc1..959d3df 100644 --- a/README.md +++ b/README.md @@ -1,37 +1,45 @@ # GDXInterface.jl -High-level Julia interface for reading and writing -[GDX files](https://gams-dev.github.io/gdx/index.html) -(GAMS Data Exchange). +[![Build Status](https://github.com/jd-foster/GDXInterface.jl/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/jd-foster/GDXInterface.jl/actions?query=workflow%3ACI) +[![codecov](https://codecov.io/gh/jd-foster/GDXInterface.jl/branch/main/graph/badge.svg)](https://codecov.io/gh/jd-foster/GDXInterface.jl) -Uses the [`gdx_jll`](https://github.com/JuliaBinaryWrappers/gdx_jll.jl.git) package to -provide the GDX C library independently of GAMS. - -**No GAMS installation required.** +[GDXInterface.jl](https://github.com/jd-foster/GDXInterface.jl) is an unofficial +wrapper for [gams-dev/gdx](http://github.com/gams-dev/gdx), which provides +support for reading and writing [GDX (GAMS Data Exchange) files](https://gams-dev.github.io/gdx/index.html). For more information on the GDX file format, see the blog post -['GDX source code published on GitHub'](https://www.gams.com/blog/2023/12/gdx-source-code-published-on-github/). +[GDX source code published on GitHub](https://www.gams.com/blog/2023/12/gdx-source-code-published-on-github/). -## Installation +## Affiliation -```julia -using Pkg -Pkg.add(url="https://github.com/jd-foster/GDXInterface.jl.git") -``` +This package is an unofficial Julia wrapper of [gams-dev/gdx](https://github.com/gams-dev/gdx). +It is developed and maintained by the JuMP community. It is not an official +product by [GAMS](https://gams.com). -Or in the Pkg REPL: +## Getting help -``` -pkg> add https://github.com/jd-foster/GDXInterface.jl.git -``` +If you need help, please ask a question on the [JuMP community forum](https://jump.dev/forum). -Run tests with: +If you have a reproducible example of a bug, please [open a GitHub issue](https://github.com/jd-foster/GDXInterface.jl/issues/new). -``` -pkg> test GDXInterface +## License + +`GDXInterface.jl` is licensed under the [MIT License](https://github.com/jd-foster/GDXInterface.jl/blob/main/LICENSE.md). + +`GDXInterface.jl` wraps the [official GAMS GDX project](https://github.com/GAMS-dev/gdx), +which is also licensed under the [MIT License](https://github.com/GAMS-dev/gdx/blob/main/LICENSE). +You do not need a GAMS license to use `GDXInterface.jl`. + +## Installation + +Install `GDXInterface.jl` as follows: + +```julia +using Pkg +Pkg.add(; url = "https://github.com/jd-foster/GDXInterface.jl.git") ``` -These instructions will be updated if/when the package is registered. +You do not need a GAMS installation to use `GDXInterface.jl`. ## Quick Start @@ -136,13 +144,13 @@ for (k, v) in gdx ... # iterate over symbols GAMS special values are mapped to Julia equivalents when reading: -| GAMS | Julia | Notes | -|------|-------|-------| -| `UNDEF` | `NaN` | Undefined value | -| `NA` | `NaN` | Not available | -| `+INF` | `Inf` | Positive infinity | -| `-INF` | `-Inf` | Negative infinity | -| `EPS` | `-0.0` | "Explicitly zero" in sparse data | +| GAMS | Julia | Notes | +| :------ | :----- | :------------------------------- | +| `UNDEF` | `NaN` | Undefined value | +| `NA` | `NaN` | Not available | +| `+INF` | `Inf` | Positive infinity | +| `-INF` | `-Inf` | Negative infinity | +| `EPS` | `-0.0` | "Explicitly zero" in sparse data | When writing, `NaN` maps to GAMS `NA`, `Inf`/`-Inf` map to `+INF`/`-INF`, and `-0.0` maps back to GAMS `EPS`. This preserves EPS semantics through diff --git a/src/GDXFile.jl b/src/GDXFile.jl index f44da18..d7d73e4 100644 --- a/src/GDXFile.jl +++ b/src/GDXFile.jl @@ -73,8 +73,15 @@ struct GDXVariable <: GDXSymbol records::DataFrames.DataFrame end -GDXVariable(name::String, desc::String, domain::Vector{String}, vartype::Integer, records::DataFrames.DataFrame) = - GDXVariable(name, desc, domain, VariableType(vartype), records) +function GDXVariable( + name::String, + desc::String, + domain::Vector{String}, + vartype::Integer, + records::DataFrames.DataFrame, +) + return GDXVariable(name, desc, domain, VariableType(vartype), records) +end """ GDXEquation @@ -89,8 +96,15 @@ struct GDXEquation <: GDXSymbol records::DataFrames.DataFrame end -GDXEquation(name::String, desc::String, domain::Vector{String}, equtype::Integer, records::DataFrames.DataFrame) = - GDXEquation(name, desc, domain, EquationType(equtype), records) +function GDXEquation( + name::String, + desc::String, + domain::Vector{String}, + equtype::Integer, + records::DataFrames.DataFrame, +) + return GDXEquation(name, desc, domain, EquationType(equtype), records) +end """ GDXAlias @@ -103,7 +117,9 @@ struct GDXAlias <: GDXSymbol alias_for::String end -Base.show(io::IO, a::GDXAlias) = print(io, "GDXAlias: $(a.name) -> $(a.alias_for)") +function Base.show(io::IO, a::GDXAlias) + return print(io, "GDXAlias: $(a.name) -> $(a.alias_for)") +end # ============================================================================= # Case-insensitive key helpers @@ -133,12 +149,12 @@ list_parameters(gdx) # List all parameters """ struct GDXFile path::String - _symbols::Dict{Symbol, GDXSymbol} + _symbols::Dict{Symbol,GDXSymbol} _order::Vector{Symbol} end -function GDXFile(path::String, symbols::Dict{Symbol, <:GDXSymbol}) - gdx = GDXFile(path, Dict{Symbol, GDXSymbol}(), Symbol[]) +function GDXFile(path::String, symbols::Dict{Symbol,<:GDXSymbol}) + gdx = GDXFile(path, Dict{Symbol,GDXSymbol}(), Symbol[]) for (k, v) in symbols _insert!(gdx, k, v) end @@ -146,7 +162,7 @@ function GDXFile(path::String, symbols::Dict{Symbol, <:GDXSymbol}) end function GDXFile(path::String) - return GDXFile(path, Dict{Symbol, GDXSymbol}(), Symbol[]) + return GDXFile(path, Dict{Symbol,GDXSymbol}(), Symbol[]) end function _insert!(gdx::GDXFile, key::Symbol, sym::GDXSymbol) @@ -154,7 +170,7 @@ function _insert!(gdx::GDXFile, key::Symbol, sym::GDXSymbol) if !haskey(gdx._symbols, lk) push!(gdx._order, lk) end - gdx._symbols[lk] = sym + return gdx._symbols[lk] = sym end function Base.show(io::IO, gdx::GDXFile) @@ -165,19 +181,50 @@ function Base.show(io::IO, gdx::GDXFile) vars = list_variables(gdx) eqns = list_equations(gdx) isempty(sets) || println(io, " Sets ($(length(sets))): ", join(sets, ", ")) - isempty(aliases) || println(io, " Aliases ($(length(aliases))): ", join(aliases, ", ")) - isempty(params) || println(io, " Parameters ($(length(params))): ", join(params, ", ")) - isempty(vars) || println(io, " Variables ($(length(vars))): ", join(vars, ", ")) - isempty(eqns) || println(io, " Equations ($(length(eqns))): ", join(eqns, ", ")) + isempty(aliases) || + println(io, " Aliases ($(length(aliases))): ", join(aliases, ", ")) + isempty(params) || + println(io, " Parameters ($(length(params))): ", join(params, ", ")) + isempty(vars) || + println(io, " Variables ($(length(vars))): ", join(vars, ", ")) + return isempty(eqns) || + println(io, " Equations ($(length(eqns))): ", join(eqns, ", ")) end # Symbol listing (returns original-case names) -list_sets(gdx::GDXFile) = Symbol[Symbol(gdx._symbols[k].name) for k in gdx._order if gdx._symbols[k] isa GDXSet] -list_aliases(gdx::GDXFile) = Symbol[Symbol(gdx._symbols[k].name) for k in gdx._order if gdx._symbols[k] isa GDXAlias] -list_parameters(gdx::GDXFile) = Symbol[Symbol(gdx._symbols[k].name) for k in gdx._order if gdx._symbols[k] isa GDXParameter] -list_variables(gdx::GDXFile) = Symbol[Symbol(gdx._symbols[k].name) for k in gdx._order if gdx._symbols[k] isa GDXVariable] -list_equations(gdx::GDXFile) = Symbol[Symbol(gdx._symbols[k].name) for k in gdx._order if gdx._symbols[k] isa GDXEquation] -list_symbols(gdx::GDXFile) = Symbol[Symbol(gdx._symbols[k].name) for k in gdx._order] +function list_sets(gdx::GDXFile) + return Symbol[ + Symbol(gdx._symbols[k].name) for + k in gdx._order if gdx._symbols[k] isa GDXSet + ] +end +function list_aliases(gdx::GDXFile) + return Symbol[ + Symbol(gdx._symbols[k].name) for + k in gdx._order if gdx._symbols[k] isa GDXAlias + ] +end +function list_parameters(gdx::GDXFile) + return Symbol[ + Symbol(gdx._symbols[k].name) for + k in gdx._order if gdx._symbols[k] isa GDXParameter + ] +end +function list_variables(gdx::GDXFile) + return Symbol[ + Symbol(gdx._symbols[k].name) for + k in gdx._order if gdx._symbols[k] isa GDXVariable + ] +end +function list_equations(gdx::GDXFile) + return Symbol[ + Symbol(gdx._symbols[k].name) for + k in gdx._order if gdx._symbols[k] isa GDXEquation + ] +end +function list_symbols(gdx::GDXFile) + return Symbol[Symbol(gdx._symbols[k].name) for k in gdx._order] +end """ get_symbol(gdx::GDXFile, sym) -> GDXSymbol @@ -189,7 +236,11 @@ get_symbol(gdx::GDXFile, sym::Symbol) = gdx._symbols[_symkey(sym)] get_symbol(gdx::GDXFile, sym::String) = gdx._symbols[_symkey(sym)] # Resolve alias chains to get the underlying records DataFrame -function _get_records(gdx::GDXFile, sym::GDXSymbol, seen::Set{Symbol}=Set{Symbol}()) +function _get_records( + gdx::GDXFile, + sym::GDXSymbol, + seen::Set{Symbol} = Set{Symbol}(), +) sym isa GDXAlias || return sym.records key = _symkey(sym.alias_for) key in seen && error("Cyclic alias chain detected involving '$(sym.name)'") @@ -198,15 +249,23 @@ function _get_records(gdx::GDXFile, sym::GDXSymbol, seen::Set{Symbol}=Set{Symbol end # Dictionary-like access (returns records DataFrame, resolving aliases) -Base.getindex(gdx::GDXFile, sym::Symbol) = _get_records(gdx, gdx._symbols[_symkey(sym)]) +function Base.getindex(gdx::GDXFile, sym::Symbol) + return _get_records(gdx, gdx._symbols[_symkey(sym)]) +end Base.getindex(gdx::GDXFile, sym::String) = gdx[Symbol(sym)] Base.haskey(gdx::GDXFile, sym::Symbol) = haskey(gdx._symbols, _symkey(sym)) -Base.keys(gdx::GDXFile) = Symbol[Symbol(gdx._symbols[k].name) for k in gdx._order] +function Base.keys(gdx::GDXFile) + return Symbol[Symbol(gdx._symbols[k].name) for k in gdx._order] +end Base.length(gdx::GDXFile) = length(gdx._order) # Dictionary-like setting (inserts or updates symbols) -Base.setindex!(gdx::GDXFile, sym::GDXSymbol, key::Symbol) = _insert!(gdx, key, sym) -Base.setindex!(gdx::GDXFile, sym::GDXSymbol, key::String) = _insert!(gdx, Symbol(key), sym) +function Base.setindex!(gdx::GDXFile, sym::GDXSymbol, key::Symbol) + return _insert!(gdx, key, sym) +end +function Base.setindex!(gdx::GDXFile, sym::GDXSymbol, key::String) + return _insert!(gdx, Symbol(key), sym) +end function Base.iterate(gdx::GDXFile) isempty(gdx._order) && return nothing @@ -223,8 +282,11 @@ function Base.iterate(gdx::GDXFile, state::Int) end # Property access for tab completion -function Base.propertynames(gdx::GDXFile, private::Bool=false) - (fieldnames(GDXFile)..., (Symbol(gdx._symbols[k].name) for k in gdx._order)...) +function Base.propertynames(gdx::GDXFile, private::Bool = false) + return ( + fieldnames(GDXFile)..., + (Symbol(gdx._symbols[k].name) for k in gdx._order)..., + ) end function Base.getproperty(gdx::GDXFile, sym::Symbol) @@ -258,14 +320,14 @@ demand = gdx[:demand] # Get parameter as DataFrame gdx = read_gdx("big_model.gdx", only=[:x, :demand]) ``` """ -function read_gdx(filepath::String; parse_integers::Bool=true, only=nothing) +function read_gdx(filepath::String; parse_integers::Bool = true, only = nothing) gdx = GDXHandle() gdx_create(gdx) only_filter = only === nothing ? nothing : Set{Symbol}(_symkey.(only)) try gdx_open_read(gdx, filepath) - gdxfile = GDXFile(filepath, Dict{Symbol, GDXSymbol}(), Symbol[]) + gdxfile = GDXFile(filepath, Dict{Symbol,GDXSymbol}(), Symbol[]) n_syms, n_uels = gdx_system_info(gdx) @@ -277,19 +339,65 @@ function read_gdx(filepath::String; parse_integers::Bool=true, only=nothing) continue end - sym_count, sym_user_info, sym_description = gdx_symbol_info_x(gdx, sym_nr) + sym_count, sym_user_info, sym_description = + gdx_symbol_info_x(gdx, sym_nr) if sym_type == GMS_DT_SET - _insert!(gdxfile, sym_key, _read_set(gdx, sym_nr, sym_name, sym_dim, sym_description)) + _insert!( + gdxfile, + sym_key, + _read_set(gdx, sym_nr, sym_name, sym_dim, sym_description), + ) elseif sym_type == GMS_DT_PAR - _insert!(gdxfile, sym_key, _read_parameter(gdx, sym_nr, sym_name, sym_dim, sym_description, parse_integers)) + _insert!( + gdxfile, + sym_key, + _read_parameter( + gdx, + sym_nr, + sym_name, + sym_dim, + sym_description, + parse_integers, + ), + ) elseif sym_type == GMS_DT_VAR - _insert!(gdxfile, sym_key, _read_variable(gdx, sym_nr, sym_name, sym_dim, sym_description, sym_user_info, parse_integers)) + _insert!( + gdxfile, + sym_key, + _read_variable( + gdx, + sym_nr, + sym_name, + sym_dim, + sym_description, + sym_user_info, + parse_integers, + ), + ) elseif sym_type == GMS_DT_EQU - _insert!(gdxfile, sym_key, _read_equation(gdx, sym_nr, sym_name, sym_dim, sym_description, sym_user_info, parse_integers)) + _insert!( + gdxfile, + sym_key, + _read_equation( + gdx, + sym_nr, + sym_name, + sym_dim, + sym_description, + sym_user_info, + parse_integers, + ), + ) elseif sym_type == GMS_DT_ALIAS - aliased_name = sym_user_info > 0 ? gdx_symbol_info(gdx, sym_user_info)[1] : "*" - _insert!(gdxfile, sym_key, GDXAlias(sym_name, sym_description, aliased_name)) + aliased_name = + sym_user_info > 0 ? gdx_symbol_info(gdx, sym_user_info)[1] : + "*" + _insert!( + gdxfile, + sym_key, + GDXAlias(sym_name, sym_description, aliased_name), + ) end end @@ -300,7 +408,13 @@ function read_gdx(filepath::String; parse_integers::Bool=true, only=nothing) end end -function _read_set(gdx::GDXHandle, sym_nr::Int, name::String, dim::Int, description::String) +function _read_set( + gdx::GDXHandle, + sym_nr::Int, + name::String, + dim::Int, + description::String, +) domains = dim > 0 ? gdx_symbol_get_domain_x(gdx, sym_nr, dim) : String[] n_recs = gdx_data_read_str_start(gdx, sym_nr) @@ -342,7 +456,14 @@ function _read_set(gdx::GDXHandle, sym_nr::Int, name::String, dim::Int, descript return GDXSet(name, description, domains, df) end -function _read_parameter(gdx::GDXHandle, sym_nr::Int, name::String, dim::Int, description::String, parse_integers::Bool) +function _read_parameter( + gdx::GDXHandle, + sym_nr::Int, + name::String, + dim::Int, + description::String, + parse_integers::Bool, +) domains = dim > 0 ? gdx_symbol_get_domain_x(gdx, sym_nr, dim) : String[] n_recs = gdx_data_read_str_start(gdx, sym_nr) @@ -372,13 +493,21 @@ function _read_parameter(gdx::GDXHandle, sym_nr::Int, name::String, dim::Int, de end df[!, :value] = values - DataFrames.metadata!(df, "name", name, style=:default) - DataFrames.metadata!(df, "description", description, style=:default) + DataFrames.metadata!(df, "name", name; style = :default) + DataFrames.metadata!(df, "description", description; style = :default) return GDXParameter(name, description, domains, df) end -function _read_variable(gdx::GDXHandle, sym_nr::Int, name::String, dim::Int, description::String, user_info::Int, parse_integers::Bool) +function _read_variable( + gdx::GDXHandle, + sym_nr::Int, + name::String, + dim::Int, + description::String, + user_info::Int, + parse_integers::Bool, +) domains = dim > 0 ? gdx_symbol_get_domain_x(gdx, sym_nr, dim) : String[] n_recs = gdx_data_read_str_start(gdx, sym_nr) @@ -420,13 +549,21 @@ function _read_variable(gdx::GDXHandle, sym_nr::Int, name::String, dim::Int, des df[!, :upper] = upper df[!, :scale] = scale - DataFrames.metadata!(df, "name", name, style=:default) - DataFrames.metadata!(df, "description", description, style=:default) + DataFrames.metadata!(df, "name", name; style = :default) + DataFrames.metadata!(df, "description", description; style = :default) return GDXVariable(name, description, domains, VariableType(user_info), df) end -function _read_equation(gdx::GDXHandle, sym_nr::Int, name::String, dim::Int, description::String, user_info::Int, parse_integers::Bool) +function _read_equation( + gdx::GDXHandle, + sym_nr::Int, + name::String, + dim::Int, + description::String, + user_info::Int, + parse_integers::Bool, +) domains = dim > 0 ? gdx_symbol_get_domain_x(gdx, sym_nr, dim) : String[] n_recs = gdx_data_read_str_start(gdx, sym_nr) @@ -468,8 +605,8 @@ function _read_equation(gdx::GDXHandle, sym_nr::Int, name::String, dim::Int, des df[!, :upper] = upper df[!, :scale] = scale - DataFrames.metadata!(df, "name", name, style=:default) - DataFrames.metadata!(df, "description", description, style=:default) + DataFrames.metadata!(df, "name", name; style = :default) + DataFrames.metadata!(df, "description", description; style = :default) return GDXEquation(name, description, domains, EquationType(user_info), df) end @@ -490,7 +627,11 @@ gdx = read_gdx("input.gdx") write_gdx("output.gdx", gdx) ``` """ -function write_gdx(filepath::String, gdxfile::GDXFile; producer::String="GDXInterface.jl") +function write_gdx( + filepath::String, + gdxfile::GDXFile; + producer::String = "GDXInterface.jl", +) gdx = GDXHandle() gdx_create(gdx) @@ -528,7 +669,11 @@ df = DataFrame(i=["a", "b", "c"], value=[1.0, 2.0, 3.0]) write_gdx("output.gdx", "demand" => df) ``` """ -function write_gdx(filepath::String, symbols::Pair{String, DataFrames.DataFrame}...; producer::String="GDXInterface.jl") +function write_gdx( + filepath::String, + symbols::Pair{String,DataFrames.DataFrame}...; + producer::String = "GDXInterface.jl", +) gdx = GDXHandle() gdx_create(gdx) @@ -547,10 +692,15 @@ function write_gdx(filepath::String, symbols::Pair{String, DataFrames.DataFrame} return filepath end -function _set_domain_x(gdx::GDXHandle, name::String, domain::Vector{String}, dim::Int) +function _set_domain_x( + gdx::GDXHandle, + name::String, + domain::Vector{String}, + dim::Int, +) length(domain) == dim && dim > 0 || return found, sym_nr = gdx_find_symbol(gdx, name) - found && gdx_symbol_set_domain_x(gdx, sym_nr, domain) + return found && gdx_symbol_set_domain_x(gdx, sym_nr, domain) end # Type dispatch for writing symbols @@ -586,14 +736,26 @@ function _write_set(gdx::GDXHandle, sym::GDXSet) end gdx_data_write_done(gdx) - _set_domain_x(gdx, sym.name, sym.domain, dim) + return _set_domain_x(gdx, sym.name, sym.domain, dim) end function _write_parameter(gdx::GDXHandle, sym::GDXParameter) - _write_parameter_df(gdx, sym.name, sym.records, sym.description, sym.domain) -end - -function _write_parameter_df(gdx::GDXHandle, name::String, df::DataFrames.DataFrame, description::String="", domain::Vector{String}=String[]) + return _write_parameter_df( + gdx, + sym.name, + sym.records, + sym.description, + sym.domain, + ) +end + +function _write_parameter_df( + gdx::GDXHandle, + name::String, + df::DataFrames.DataFrame, + description::String = "", + domain::Vector{String} = String[], +) dim_cols = [n for n in names(df) if n != "value"] dim = length(dim_cols) @@ -611,7 +773,7 @@ function _write_parameter_df(gdx::GDXHandle, name::String, df::DataFrames.DataFr end gdx_data_write_done(gdx) - _set_domain_x(gdx, name, domain, dim) + return _set_domain_x(gdx, name, domain, dim) end const _VAR_EQU_COLS = Set(["level", "marginal", "lower", "upper", "scale"]) @@ -621,7 +783,14 @@ function _write_variable(gdx::GDXHandle, sym::GDXVariable) dim_cols = [n for n in names(df) if !(n in _VAR_EQU_COLS)] dim = length(dim_cols) - gdx_data_write_str_start(gdx, sym.name, sym.description, dim, GMS_DT_VAR, Int(sym.vartype)) + gdx_data_write_str_start( + gdx, + sym.name, + sym.description, + dim, + GMS_DT_VAR, + Int(sym.vartype), + ) keys = Vector{String}(undef, dim) vals = zeros(Float64, GMS_VAL_MAX) @@ -639,7 +808,7 @@ function _write_variable(gdx::GDXHandle, sym::GDXVariable) end gdx_data_write_done(gdx) - _set_domain_x(gdx, sym.name, sym.domain, dim) + return _set_domain_x(gdx, sym.name, sym.domain, dim) end function _write_equation(gdx::GDXHandle, sym::GDXEquation) @@ -647,7 +816,14 @@ function _write_equation(gdx::GDXHandle, sym::GDXEquation) dim_cols = [n for n in names(df) if !(n in _VAR_EQU_COLS)] dim = length(dim_cols) - gdx_data_write_str_start(gdx, sym.name, sym.description, dim, GMS_DT_EQU, Int(sym.equtype)) + gdx_data_write_str_start( + gdx, + sym.name, + sym.description, + dim, + GMS_DT_EQU, + Int(sym.equtype), + ) keys = Vector{String}(undef, dim) vals = zeros(Float64, GMS_VAL_MAX) @@ -665,7 +841,7 @@ function _write_equation(gdx::GDXHandle, sym::GDXEquation) end gdx_data_write_done(gdx) - _set_domain_x(gdx, sym.name, sym.domain, dim) + return _set_domain_x(gdx, sym.name, sym.domain, dim) end # ============================================================================= diff --git a/src/GDXInterface.jl b/src/GDXInterface.jl index a016379..5e4617a 100644 --- a/src/GDXInterface.jl +++ b/src/GDXInterface.jl @@ -8,12 +8,24 @@ include("gdx_c_api.jl") include("GDXFile.jl") # GDX file access exports -export GDXFile, GDXSymbol, GDXSet, GDXParameter, GDXVariable, GDXEquation, GDXAlias +export GDXFile, + GDXSymbol, GDXSet, GDXParameter, GDXVariable, GDXEquation, GDXAlias export GDXException -export VariableType, VarUnknown, VarBinary, VarInteger, VarPositive, VarNegative, VarFree, VarSOS1, VarSOS2, VarSemiCont, VarSemiInt +export VariableType, + VarUnknown, + VarBinary, + VarInteger, + VarPositive, + VarNegative, + VarFree, + VarSOS1, + VarSOS2, + VarSemiCont, + VarSemiInt export EquationType, EqE, EqG, EqL, EqN, EqX, EqC, EqB export read_gdx, write_gdx -export list_sets, list_aliases, list_parameters, list_variables, list_equations, list_symbols +export list_sets, + list_aliases, list_parameters, list_variables, list_equations, list_symbols export get_symbol end # module GDXInterface diff --git a/src/gdx_c_api.jl b/src/gdx_c_api.jl index 8e12311..21250ab 100644 --- a/src/gdx_c_api.jl +++ b/src/gdx_c_api.jl @@ -4,7 +4,7 @@ # libgdx C library prefix for ccall: const GDX_C_PREFIX = "c__" macro cpfx(x) - s = strip(string(x),':') + s = strip(string(x), ':') return Expr(:quote, Symbol(GDX_C_PREFIX, s)) end @@ -40,7 +40,6 @@ const GAMS_SV_EPS = 5.0e300 # epsilon const GAMS_SV_ACR = 10.0e300 # potential / real acronym const GAMS_SV_NAINT = 2100000000 # not available / applicable for integers - function parse_gdx_value(val::Float64) if val == GAMS_SV_UNDEF || val == GAMS_SV_NA return NaN @@ -81,7 +80,16 @@ mutable struct GDXHandle cbuf = pointer.(buf) crvec = Vector{Cdouble}(undef, GMS_VAL_MAX) civec = Vector{Cint}(undef, GMS_MAX_INDEX_DIM) - return new(cptr, Ref{Cint}(-1), Ref{Cint}(-1), Ref{Cint}(-1), civec, crvec, buf, cbuf) + return new( + cptr, + Ref{Cint}(-1), + Ref{Cint}(-1), + Ref{Cint}(-1), + civec, + crvec, + buf, + cbuf, + ) end end @@ -90,7 +98,9 @@ struct GDXException <: Exception n_err::Int end -Base.showerror(io::IO, e::GDXException) = print(io, "GDX failed: $(e.msg) ($(e.n_err))") +function Base.showerror(io::IO, e::GDXException) + return print(io, "GDX failed: $(e.msg) ($(e.n_err))") +end # ============================================================================= # Core handle management @@ -136,7 +146,12 @@ function gdx_open_read(gdx::GDXHandle, file::String) return rc end -function gdx_open_write(gdx_ptr::Ptr{Cvoid}, file::String, producer::String, n_err::Ref{Cint}) +function gdx_open_write( + gdx_ptr::Ptr{Cvoid}, + file::String, + producer::String, + n_err::Ref{Cint}, +) return ccall( (@cpfx(:gdxopenwrite), LIBGDX), Cint, @@ -148,7 +163,11 @@ function gdx_open_write(gdx_ptr::Ptr{Cvoid}, file::String, producer::String, n_e ) end -function gdx_open_write(gdx::GDXHandle, file::String, producer::String="GAMS.jl") +function gdx_open_write( + gdx::GDXHandle, + file::String, + producer::String = "GAMS.jl", +) rc = gdx_open_write(gdx.cptr[], file, producer, gdx.cival) if gdx.cival[] != 0 || rc != 1 throw(GDXException("Can't open file '$file' for writing", gdx.cival[])) @@ -156,7 +175,9 @@ function gdx_open_write(gdx::GDXHandle, file::String, producer::String="GAMS.jl" return end -gdx_close(gdx_ptr::Ptr{Cvoid}) = ccall((@cpfx(:gdxclose), LIBGDX), Cint, (Ptr{Cvoid},), gdx_ptr) +function gdx_close(gdx_ptr::Ptr{Cvoid}) + return ccall((@cpfx(:gdxclose), LIBGDX), Cint, (Ptr{Cvoid},), gdx_ptr) +end function gdx_close(gdx::GDXHandle) gdx_close(gdx.cptr[]) @@ -167,7 +188,11 @@ end # System and symbol information # ============================================================================= -function gdx_system_info(gdx_ptr::Ptr{Cvoid}, sym_count::Ref{Cint}, uel_count::Ref{Cint}) +function gdx_system_info( + gdx_ptr::Ptr{Cvoid}, + sym_count::Ref{Cint}, + uel_count::Ref{Cint}, +) return ccall( (@cpfx(:gdxsysteminfo), LIBGDX), Cint, @@ -235,7 +260,13 @@ end function gdx_symbol_info_x(gdx::GDXHandle, sym_id::Int) gdx.buf[1][1] = UInt8('\0') - rc = gdx_symbol_info_x(gdx.cptr[], sym_id, gdx.cival, gdx.cival2, gdx.cbuf[1]) + rc = gdx_symbol_info_x( + gdx.cptr[], + sym_id, + gdx.cival, + gdx.cival2, + gdx.cbuf[1], + ) if rc != 1 throw(GDXException("Can't read extended symbol info", 0)) end @@ -258,7 +289,11 @@ function gdx_find_symbol(gdx::GDXHandle, name::String) return rc == 1, Int(gdx.cival[]) end -function gdx_symbol_get_domain_x(gdx_ptr::Ptr{Cvoid}, sym_nr::Int, domains::Vector{Ptr{UInt8}}) +function gdx_symbol_get_domain_x( + gdx_ptr::Ptr{Cvoid}, + sym_nr::Int, + domains::Vector{Ptr{UInt8}}, +) return ccall( (@cpfx(:gdxsymbolgetdomainx), LIBGDX), Cint, @@ -281,7 +316,11 @@ function gdx_symbol_get_domain_x(gdx::GDXHandle, sym_nr::Int, dim::Int) return domains end -function gdx_symbol_set_domain_x(gdx_ptr::Ptr{Cvoid}, sym_nr::Int, domain_ids::Vector{String}) +function gdx_symbol_set_domain_x( + gdx_ptr::Ptr{Cvoid}, + sym_nr::Int, + domain_ids::Vector{String}, +) return ccall( (@cpfx(:gdxsymbolsetdomainx), LIBGDX), Cint, @@ -292,7 +331,11 @@ function gdx_symbol_set_domain_x(gdx_ptr::Ptr{Cvoid}, sym_nr::Int, domain_ids::V ) end -function gdx_symbol_set_domain_x(gdx::GDXHandle, sym_nr::Int, domain_ids::Vector{String}) +function gdx_symbol_set_domain_x( + gdx::GDXHandle, + sym_nr::Int, + domain_ids::Vector{String}, +) rc = gdx_symbol_set_domain_x(gdx.cptr[], sym_nr, domain_ids) return rc end @@ -324,7 +367,12 @@ end # Set element text # ============================================================================= -function gdx_get_elem_text(gdx_ptr::Ptr{Cvoid}, text_nr::Int, text::Ptr{UInt8}, node::Ref{Cint}) +function gdx_get_elem_text( + gdx_ptr::Ptr{Cvoid}, + text_nr::Int, + text::Ptr{UInt8}, + node::Ref{Cint}, +) return ccall( (@cpfx(:gdxgetelemtext), LIBGDX), Cint, @@ -365,7 +413,12 @@ end # UEL (Unique Element List) operations # ============================================================================= -function gdx_um_uel_get(gdx_ptr::Ptr{Cvoid}, uel_nr::Int, uel::Ptr{UInt8}, uel_map::Ref{Cint}) +function gdx_um_uel_get( + gdx_ptr::Ptr{Cvoid}, + uel_nr::Int, + uel::Ptr{UInt8}, + uel_map::Ref{Cint}, +) return ccall( (@cpfx(:gdxumuelget), LIBGDX), Cint, @@ -387,7 +440,12 @@ function gdx_um_uel_get(gdx::GDXHandle, uel_nr::Int) end function gdx_uel_register_str_start(gdx_ptr::Ptr{Cvoid}) - return ccall((@cpfx(:gdxuelregisterstrstart), LIBGDX), Cint, (Ptr{Cvoid},), gdx_ptr) + return ccall( + (@cpfx(:gdxuelregisterstrstart), LIBGDX), + Cint, + (Ptr{Cvoid},), + gdx_ptr, + ) end function gdx_uel_register_str_start(gdx::GDXHandle) @@ -398,7 +456,11 @@ function gdx_uel_register_str_start(gdx::GDXHandle) return end -function gdx_uel_register_str(gdx_ptr::Ptr{Cvoid}, uel::String, uel_nr::Ref{Cint}) +function gdx_uel_register_str( + gdx_ptr::Ptr{Cvoid}, + uel::String, + uel_nr::Ref{Cint}, +) return ccall( (@cpfx(:gdxuelregisterstr), LIBGDX), Cint, @@ -415,7 +477,12 @@ function gdx_uel_register_str(gdx::GDXHandle, uel::String) end function gdx_uel_register_done(gdx_ptr::Ptr{Cvoid}) - return ccall((@cpfx(:gdxuelregisterdone), LIBGDX), Cint, (Ptr{Cvoid},), gdx_ptr) + return ccall( + (@cpfx(:gdxuelregisterdone), LIBGDX), + Cint, + (Ptr{Cvoid},), + gdx_ptr, + ) end function gdx_uel_register_done(gdx::GDXHandle) @@ -430,7 +497,11 @@ end # Reading data (raw integer interface) # ============================================================================= -function gdx_data_read_raw_start(gdx_ptr::Ptr{Cvoid}, start::Int, n_rec::Ref{Cint}) +function gdx_data_read_raw_start( + gdx_ptr::Ptr{Cvoid}, + start::Int, + n_rec::Ref{Cint}, +) return ccall( (@cpfx(:gdxdatareadrawstart), LIBGDX), Cint, @@ -466,7 +537,11 @@ function gdx_data_read_raw( ) end -function gdx_data_read_raw(gdx::GDXHandle, idx::Vector{Int}, vals::Vector{Float64}) +function gdx_data_read_raw( + gdx::GDXHandle, + idx::Vector{Int}, + vals::Vector{Float64}, +) @assert(length(idx) <= length(gdx.civec)) @assert(length(vals) <= length(gdx.crvec)) @@ -488,7 +563,11 @@ end # Reading data (string interface) # ============================================================================= -function gdx_data_read_str_start(gdx_ptr::Ptr{Cvoid}, start::Int, n_err::Ref{Cint}) +function gdx_data_read_str_start( + gdx_ptr::Ptr{Cvoid}, + start::Int, + n_err::Ref{Cint}, +) return ccall( (@cpfx(:gdxdatareadstrstart), LIBGDX), Cint, @@ -524,7 +603,11 @@ function gdx_data_read_str( ) end -function gdx_data_read_str(gdx::GDXHandle, keystr::Vector{String}, vals::Vector{Float64}) +function gdx_data_read_str( + gdx::GDXHandle, + keystr::Vector{String}, + vals::Vector{Float64}, +) @assert(length(keystr) <= length(gdx.cbuf)) @assert(length(vals) <= length(gdx.crvec)) @@ -547,7 +630,12 @@ function gdx_data_read_str(gdx::GDXHandle, keystr::Vector{String}, vals::Vector{ end function gdx_data_read_done(gdx_ptr::Ptr{Cvoid}) - return ccall((@cpfx(:gdxdatareaddone), LIBGDX), Cint, (Ptr{Cvoid},), gdx_ptr) + return ccall( + (@cpfx(:gdxdatareaddone), LIBGDX), + Cint, + (Ptr{Cvoid},), + gdx_ptr, + ) end function gdx_data_read_done(gdx::GDXHandle) @@ -580,7 +668,14 @@ function gdx_data_write_str_start( ) end -function gdx_data_write_str_start(gdx::GDXHandle, name::String, text::String, dim::Int, typ::Int, user_info::Int=0) +function gdx_data_write_str_start( + gdx::GDXHandle, + name::String, + text::String, + dim::Int, + typ::Int, + user_info::Int = 0, +) rc = gdx_data_write_str_start(gdx.cptr[], name, text, dim, typ, user_info) if rc != 1 throw(GDXException("Can't start writing symbol '$name'", 0)) @@ -588,7 +683,11 @@ function gdx_data_write_str_start(gdx::GDXHandle, name::String, text::String, di return end -function gdx_data_write_str(gdx_ptr::Ptr{Cvoid}, keys::Vector{String}, vals::Vector{Float64}) +function gdx_data_write_str( + gdx_ptr::Ptr{Cvoid}, + keys::Vector{String}, + vals::Vector{Float64}, +) return ccall( (@cpfx(:gdxdatawritestr), LIBGDX), Cint, @@ -599,7 +698,11 @@ function gdx_data_write_str(gdx_ptr::Ptr{Cvoid}, keys::Vector{String}, vals::Vec ) end -function gdx_data_write_str(gdx::GDXHandle, keys::Vector{String}, vals::Vector{Float64}) +function gdx_data_write_str( + gdx::GDXHandle, + keys::Vector{String}, + vals::Vector{Float64}, +) rc = gdx_data_write_str(gdx.cptr[], keys, vals) if rc != 1 throw(GDXException("Can't write record", 0)) @@ -608,7 +711,12 @@ function gdx_data_write_str(gdx::GDXHandle, keys::Vector{String}, vals::Vector{F end function gdx_data_write_done(gdx_ptr::Ptr{Cvoid}) - return ccall((@cpfx(:gdxdatawritedone), LIBGDX), Cint, (Ptr{Cvoid},), gdx_ptr) + return ccall( + (@cpfx(:gdxdatawritedone), LIBGDX), + Cint, + (Ptr{Cvoid},), + gdx_ptr, + ) end function gdx_data_write_done(gdx::GDXHandle) diff --git a/test/test_gdxfile.jl b/test/test_gdxfile.jl index 9cc8935..a05d602 100644 --- a/test/test_gdxfile.jl +++ b/test/test_gdxfile.jl @@ -52,13 +52,10 @@ execute_unload "gams_gdx_test.gdx", i, p, x, y; end @testset "Write and read round-trip" begin - supply = DataFrame( - i = ["seattle", "san-diego"], - value = [350.0, 600.0] - ) + supply = DataFrame(i = ["seattle", "san-diego"], value = [350.0, 600.0]) demand = DataFrame( j = ["new-york", "chicago", "topeka"], - value = [325.0, 300.0, 275.0] + value = [325.0, 300.0, 275.0], ) outfile = joinpath(tempdir(), "gdx_jl_write_test.gdx") @@ -74,14 +71,14 @@ execute_unload "gams_gdx_test.gdx", i, p, x, y; @test gdxfile.supply == gdxfile[:supply] @test gdxfile.demand == gdxfile[:demand] - rm(outfile, force=true) + rm(outfile, force = true) end @testset "Multi-dimensional parameters" begin cost = DataFrame( i = ["seattle", "seattle", "san-diego", "san-diego"], j = ["new-york", "chicago", "new-york", "chicago"], - value = [2.5, 1.7, 2.5, 1.8] + value = [2.5, 1.7, 2.5, 1.8], ) outfile = joinpath(tempdir(), "gdx_jl_2d_test.gdx") @@ -94,7 +91,7 @@ execute_unload "gams_gdx_test.gdx", i, p, x, y; @test length(names(result)) == 3 @test "value" in names(result) - rm(outfile, force=true) + rm(outfile, force = true) end @testset "Integer parsing" begin @@ -103,13 +100,13 @@ execute_unload "gams_gdx_test.gdx", i, p, x, y; outfile = joinpath(tempdir(), "gdx_jl_int_test.gdx") write_gdx(outfile, "data" => df) - gdxfile = read_gdx(outfile, parse_integers=true) + gdxfile = read_gdx(outfile, parse_integers = true) @test eltype(gdxfile[:data].dim1) == Int - gdxfile = read_gdx(outfile, parse_integers=false) + gdxfile = read_gdx(outfile, parse_integers = false) @test eltype(gdxfile[:data].dim1) == String - rm(outfile, force=true) + rm(outfile, force = true) end @testset "GDXFile show and propertynames" begin @@ -128,7 +125,7 @@ execute_unload "gams_gdx_test.gdx", i, p, x, y; props = propertynames(gdxfile) @test :param in props - rm(outfile, force=true) + rm(outfile, force = true) end @testset "Symbol listing" begin @@ -148,7 +145,7 @@ execute_unload "gams_gdx_test.gdx", i, p, x, y; syms = list_symbols(gdxfile) @test length(syms) == 2 - rm(outfile, force=true) + rm(outfile, force = true) end @testset "GDXFile full round-trip (sets, params, variables)" begin @@ -172,11 +169,14 @@ execute_unload "gams_gdx_test.gdx", i, p, x, y; # Sets match (compare first column values) @test sort(Vector(gdx1[:i][!, 1])) == sort(Vector(gdx2[:i][!, 1])) - rm(outfile, force=true) + rm(outfile, force = true) end @testset "Special values round-trip" begin - df = DataFrame(i = ["a", "b", "c", "d", "e"], value = [NaN, Inf, -Inf, 42.0, -0.0]) + df = DataFrame( + i = ["a", "b", "c", "d", "e"], + value = [NaN, Inf, -Inf, 42.0, -0.0], + ) outfile = joinpath(tempdir(), "gdx_jl_special.gdx") write_gdx(outfile, "special" => df) @@ -188,7 +188,7 @@ execute_unload "gams_gdx_test.gdx", i, p, x, y; @test result.value[4] == 42.0 @test result.value[5] === -0.0 - rm(outfile, force=true) + rm(outfile, force = true) end @testset "Scalar (0-dim) parameters" begin @@ -201,12 +201,12 @@ execute_unload "gams_gdx_test.gdx", i, p, x, y; @test gdxfile[:scalar_param].value == [42.0] @test size(gdxfile[:scalar_param], 2) == 1 # only the value column - rm(outfile, force=true) + rm(outfile, force = true) end @testset "Selective reading (only keyword)" begin gdx_full = read_gdx(test_gdx) - gdx_partial = read_gdx(test_gdx, only=[:p, :x]) + gdx_partial = read_gdx(test_gdx, only = [:p, :x]) @test length(gdx_partial) == 2 @test :p in list_parameters(gdx_partial) @@ -216,7 +216,7 @@ execute_unload "gams_gdx_test.gdx", i, p, x, y; @test gdx_partial[:p].value == gdx_full[:p].value # String names should also work - gdx_str = read_gdx(test_gdx, only=["i"]) + gdx_str = read_gdx(test_gdx, only = ["i"]) @test length(gdx_str) == 1 @test :i in list_sets(gdx_str) end @@ -260,7 +260,7 @@ execute_unload "gams_gdx_test.gdx", i, p, x, y; marginal = [0.5, 0.6], lower = [-Inf, -Inf], upper = [Inf, Inf], - scale = [1.0, 1.0] + scale = [1.0, 1.0], ) eq = GDXEquation("myeq", "test equation", ["i"], 0, eq_df) gdxfile = GDXFile("", Dict{Symbol,GDXSymbol}(:myeq => eq)) @@ -273,7 +273,7 @@ execute_unload "gams_gdx_test.gdx", i, p, x, y; @test gdx2[:myeq].level == [1.0, 2.0] @test gdx2[:myeq].marginal == [0.5, 0.6] - rm(outfile, force=true) + rm(outfile, force = true) end @testset "Writing sets standalone" begin @@ -288,7 +288,7 @@ execute_unload "gams_gdx_test.gdx", i, p, x, y; @test :myset in list_sets(gdx2) @test sort(Vector(gdx2[:myset][!, 1])) == ["x", "y", "z"] - rm(outfile, force=true) + rm(outfile, force = true) end @testset "Variable/Equation type enums" begin @@ -302,10 +302,34 @@ execute_unload "gams_gdx_test.gdx", i, p, x, y; @test sym_y.vartype == VarPositive # Integer constructor still works - v = GDXVariable("test", "", String[], 3, DataFrame(level=[0.0], marginal=[0.0], lower=[0.0], upper=[0.0], scale=[1.0])) + v = GDXVariable( + "test", + "", + String[], + 3, + DataFrame( + level = [0.0], + marginal = [0.0], + lower = [0.0], + upper = [0.0], + scale = [1.0], + ), + ) @test v.vartype == VarPositive - e = GDXEquation("test", "", String[], 0, DataFrame(level=[0.0], marginal=[0.0], lower=[0.0], upper=[0.0], scale=[1.0])) + e = GDXEquation( + "test", + "", + String[], + 0, + DataFrame( + level = [0.0], + marginal = [0.0], + lower = [0.0], + upper = [0.0], + scale = [1.0], + ), + ) @test e.equtype == EqE end @@ -325,7 +349,7 @@ execute_unload "gams_gdx_test.gdx", i, p, x, y; @test sym.name == "p" # Selective read is also case-insensitive - gdx2 = read_gdx(test_gdx, only=[:P, :X]) + gdx2 = read_gdx(test_gdx, only = [:P, :X]) @test length(gdx2) == 2 @test :p in list_parameters(gdx2) @test :x in list_variables(gdx2) @@ -345,13 +369,13 @@ execute_unload "gams_gdx_test.gdx", i, p, x, y; gdx2 = read_gdx(outfile) @test list_symbols(gdx2) == syms - rm(outfile, force=true) + rm(outfile, force = true) end @testset "Set element text round-trip" begin set_df = DataFrame( dim1 = ["seattle", "san-diego", "topeka"], - element_text = ["rainy city", "sunny city", ""] + element_text = ["rainy city", "sunny city", ""], ) s = GDXSet("cities", "transport cities", ["*"], set_df) gdxfile = GDXFile("", Dict{Symbol,GDXSymbol}(:cities => s)) @@ -366,7 +390,7 @@ execute_unload "gams_gdx_test.gdx", i, p, x, y; @test result.element_text[2] == "sunny city" @test result.element_text[3] == "" - rm(outfile, force=true) + rm(outfile, force = true) end @testset "Set without element text has no extra column" begin @@ -380,7 +404,7 @@ execute_unload "gams_gdx_test.gdx", i, p, x, y; gdx2 = read_gdx(outfile) @test !("element_text" in names(gdx2[:simple])) - rm(outfile, force=true) + rm(outfile, force = true) end @testset "Alias round-trip" begin @@ -403,7 +427,7 @@ execute_unload "gams_gdx_test.gdx", i, p, x, y; # Accessing alias records resolves to the aliased set's records @test gdx2[:j] == gdx2[:i] - rm(outfile, force=true) + rm(outfile, force = true) end @testset "GDXAlias show" begin @@ -428,7 +452,7 @@ execute_unload "gams_gdx_test.gdx", i, p, x, y; @test x2.domain == ["i"] @test names(gdx2[:x])[1] == "i" - rm(outfile, force=true) + rm(outfile, force = true) end @testset "Domain preservation for variables (issue #3)" begin @@ -440,7 +464,7 @@ execute_unload "gams_gdx_test.gdx", i, p, x, y; marginal = [0.0, 0.0, 0.0], lower = [-Inf, -Inf, -Inf], upper = [Inf, Inf, Inf], - scale = [1.0, 1.0, 1.0] + scale = [1.0, 1.0, 1.0], ) v = GDXVariable("y", "A variable over i", ["i"], VarFree, var_df) gdxfile = GDXFile("", Dict{Symbol,GDXSymbol}(:i => s, :y => v)) @@ -453,7 +477,7 @@ execute_unload "gams_gdx_test.gdx", i, p, x, y; @test y2.domain == ["i"] @test names(gdx2[:y])[1] == "i" - rm(outfile, force=true) + rm(outfile, force = true) end @testset "Domain preservation for equations (issue #3)" begin @@ -465,7 +489,7 @@ execute_unload "gams_gdx_test.gdx", i, p, x, y; marginal = [0.5, 0.6], lower = [-Inf, -Inf], upper = [Inf, Inf], - scale = [1.0, 1.0] + scale = [1.0, 1.0], ) eq = GDXEquation("myeq", "test eq", ["i"], EqE, eq_df) gdxfile = GDXFile("", Dict{Symbol,GDXSymbol}(:i => s, :myeq => eq)) @@ -478,7 +502,7 @@ execute_unload "gams_gdx_test.gdx", i, p, x, y; @test eq2.domain == ["i"] @test names(gdx2[:myeq])[1] == "i" - rm(outfile, force=true) + rm(outfile, force = true) end @testset "Multi-dimensional domain preservation (issue #3)" begin @@ -487,10 +511,11 @@ execute_unload "gams_gdx_test.gdx", i, p, x, y; par_df = DataFrame( i = ["a", "a", "b", "b"], j = ["x", "y", "x", "y"], - value = [1.0, 2.0, 3.0, 4.0] + value = [1.0, 2.0, 3.0, 4.0], ) p = GDXParameter("cost", "transport cost", ["i", "j"], par_df) - gdxfile = GDXFile("", Dict{Symbol,GDXSymbol}(:i => si, :j => sj, :cost => p)) + gdxfile = + GDXFile("", Dict{Symbol,GDXSymbol}(:i => si, :j => sj, :cost => p)) outfile = joinpath(tempdir(), "gdx_jl_domain_2d_test.gdx") write_gdx(outfile, gdxfile) @@ -500,7 +525,7 @@ execute_unload "gams_gdx_test.gdx", i, p, x, y; @test cost2.domain == ["i", "j"] @test names(gdx2[:cost])[1:2] == ["i", "j"] - rm(outfile, force=true) + rm(outfile, force = true) end @testset "Domain preservation with GAMS-generated file (issue #3)" begin @@ -520,10 +545,9 @@ execute_unload "gams_gdx_test.gdx", i, p, x, y; x2 = get_symbol(gdx2, :x) @test x2.domain == x1.domain - rm(outfile, force=true) + rm(outfile, force = true) end - @testset "Setting symbols via indexing" begin gdxfile = GDXFile("") From 7441001b8d38b3061659404ef1a043c7c12b00bd Mon Sep 17 00:00:00 2001 From: Martin Kirk Bonde Date: Fri, 12 Jun 2026 11:05:42 +0200 Subject: [PATCH 2/2] Fix JuliaFormatter indentation in GDXFile.show Align continuation line after `return` with formatter rules. --- src/GDXFile.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/GDXFile.jl b/src/GDXFile.jl index 2dab906..37fe65f 100644 --- a/src/GDXFile.jl +++ b/src/GDXFile.jl @@ -197,7 +197,7 @@ function Base.show(io::IO, gdx::GDXFile) isempty(vars) || println(io, " Variables ($(length(vars))): ", join(vars, ", ")) return isempty(eqns) || - println(io, " Equations ($(length(eqns))): ", join(eqns, ", ")) + println(io, " Equations ($(length(eqns))): ", join(eqns, ", ")) end # Symbol listing (returns original-case names)