caconcat.gms : Test Connect agent Concatenate

Description

This test ensures the correctness of the Connect agent Concatenate.

Contributor: Aileen Böhme, August 2022


Small Model of Type : GAMS


Category : GAMS Test library


Main file : caconcat.gms

$title 'Test Connect agent Concatenate' (CACONCAT,SEQ=918)
$onText
This test ensures the correctness of the Connect agent Concatenate.

Contributor: Aileen Böhme, August 2022
$offText


$log --- Using Python library %sysEnv.GMSPYTHONLIB%

$onEcho > t.gms
Set i(*) canning plants /
'seattle', 
'san-diego' /;

Set j(*) markets /
'new-york', 
'chicago', 
'topeka' /;

Parameter a(i) capacity of plant i in cases /
'seattle' 350, 
'san-diego' 600 /;

Parameter b(j) demand at market j in cases /
'new-york' 325, 
'chicago' 300, 
'topeka' 275 /;

Parameter d(i,j) distance in thousands of miles /
'seattle'.'new-york' 2.5, 
'seattle'.'chicago' 1.7, 
'seattle'.'topeka' 1.8, 
'san-diego'.'new-york' 2.5, 
'san-diego'.'chicago' 1.8, 
'san-diego'.'topeka' 1.4 /;

Scalar f freight in dollars per case per thousand miles / 90 /;

Parameter c(i,j) transport cost in thousands of dollars per case /
'seattle'.'new-york' 0.225, 
'seattle'.'chicago' 0.153, 
'seattle'.'topeka' 0.162, 
'san-diego'.'new-york' 0.225, 
'san-diego'.'chicago' 0.162, 
'san-diego'.'topeka' 0.126 /;

positive Variable x(i,j) shipment quantities in cases /
'seattle'.'new-york'.L 50, 
'seattle'.'chicago'.L 300, 
'seattle'.'topeka'.M 0.036, 
'san-diego'.'new-york'.L 275, 
'san-diego'.'chicago'.M 0.00900000000000001, 
'san-diego'.'topeka'.L 275 /;

free     Variable z total transportation costs in thousands of dollars /L 153.675 /;

Equation cost define objective function /M 1, LO 0, UP 0 /;

Equation supply(i) observe supply limit at plant i /
'seattle'.L 350, 
'seattle'.M Eps, 
'seattle'.LO -Inf, 
'seattle'.UP 350, 
'san-diego'.L 550, 
'san-diego'.LO -Inf, 
'san-diego'.UP 600 /;

Equation demand(j) satisfy demand at market j /
'new-york'.L 325, 
'new-york'.M 0.225, 
'new-york'.LO 325, 
'new-york'.UP +Inf, 
'chicago'.L 300, 
'chicago'.M 0.153, 
'chicago'.LO 300, 
'chicago'.UP +Inf, 
'topeka'.L 275, 
'topeka'.M 0.126, 
'topeka'.LO 275, 
'topeka'.UP +Inf /;
$offEcho
$call.checkErrorLevel gams t.gms lo=%gams.lo% a=c gdx=t.gdx

$log test invalid number of dimensions
$onEmbeddedCode Connect:
- GDXReader:
    file: t.gdx
    readAll: True
- Concatenate:
    symbols:
        - name: a(i,j)
$offEmbeddedCode
$if errorFree $abort 'Expect errors'
$clearErrors

$log test invalid universal dimension
$onEmbeddedCode Connect:
- GDXReader:
    file: t.gdx
    readAll: True
- Concatenate:
    outputDimensions: [uni_0]
    symbols:
        - name: d(i,uni_0)
$offEmbeddedCode
$if errorFree $abort 'Expect errors'
$clearErrors

$log test invalid output dimension
$onEmbeddedCode Connect:
- GDXReader:
    file: t.gdx
    readAll: True
- Concatenate:
    outputDimensions: [i.1,i1,i-1,j]
    symbols:
        - name: a
$offEmbeddedCode
$clearErrors

$log test concatenateAll: True and outputDimensions: []
$onEmbeddedCode Connect:
- GDXReader:
    file: t.gdx
    readAll: True
- Projection:
    name: x.all(i,j)
    newName: xp(i,j)
- Projection:
    name: demand.l(j)
    newName: demand_level(j)
- Concatenate:
    outputDimensions: []
    concatenateAll: True
- GDXWriter:
    file: concat.gdx
    symbols:
        - name: setOutput
        - name: parameterOutput
$offEmbeddedCode

$call 'gdxdump concat.gdx > concat.txt'
$call 'gdxdump concat.gdx domainInfo >> concat.txt'
$onEcho > concatExpected.txt
$onEmpty

Set setOutput(*,*,*,*) /
'i'.'seattle'.'-'.'-', 
'i'.'san-diego'.'-'.'-', 
'j'.'new-york'.'-'.'-', 
'j'.'chicago'.'-'.'-', 
'j'.'topeka'.'-'.'-' /;

Parameter parameterOutput(*,*,*,*) /
'a'.'seattle'.'-'.'-' 350, 
'a'.'san-diego'.'-'.'-' 600, 
'b'.'new-york'.'-'.'-' 325, 
'b'.'chicago'.'-'.'-' 300, 
'b'.'topeka'.'-'.'-' 275, 
'd'.'seattle'.'new-york'.'-' 2.5, 
'd'.'seattle'.'chicago'.'-' 1.7, 
'd'.'seattle'.'topeka'.'-' 1.8, 
'd'.'san-diego'.'new-york'.'-' 2.5, 
'd'.'san-diego'.'chicago'.'-' 1.8, 
'd'.'san-diego'.'topeka'.'-' 1.4, 
'f'.'-'.'-'.'-' 90, 
'c'.'seattle'.'new-york'.'-' 0.225, 
'c'.'seattle'.'chicago'.'-' 0.153, 
'c'.'seattle'.'topeka'.'-' 0.162, 
'c'.'san-diego'.'new-york'.'-' 0.225, 
'c'.'san-diego'.'chicago'.'-' 0.162, 
'c'.'san-diego'.'topeka'.'-' 0.126, 
'xp'.'seattle'.'new-york'.'level' 50, 
'xp'.'seattle'.'new-york'.'upper' +Inf, 
'xp'.'seattle'.'new-york'.'scale' 1, 
'xp'.'seattle'.'chicago'.'level' 300, 
'xp'.'seattle'.'chicago'.'upper' +Inf, 
'xp'.'seattle'.'chicago'.'scale' 1, 
'xp'.'seattle'.'topeka'.'marginal' 0.036, 
'xp'.'seattle'.'topeka'.'upper' +Inf, 
'xp'.'seattle'.'topeka'.'scale' 1, 
'xp'.'san-diego'.'new-york'.'level' 275, 
'xp'.'san-diego'.'new-york'.'upper' +Inf, 
'xp'.'san-diego'.'new-york'.'scale' 1, 
'xp'.'san-diego'.'chicago'.'marginal' 0.00900000000000001, 
'xp'.'san-diego'.'chicago'.'upper' +Inf, 
'xp'.'san-diego'.'chicago'.'scale' 1, 
'xp'.'san-diego'.'topeka'.'level' 275, 
'xp'.'san-diego'.'topeka'.'upper' +Inf, 
'xp'.'san-diego'.'topeka'.'scale' 1, 
'demand_level'.'new-york'.'-'.'-' 325, 
'demand_level'.'chicago'.'-'.'-' 300, 
'demand_level'.'topeka'.'-'.'-' 275 /;

$offEmpty
SyNr  Type  DomInf Symbol
   2   Par Relaxed parameterOutput(symbols, uni_0, uni_1, uni_2)
   1   Set Relaxed setOutput(symbols, uni_0, uni_1, uni_2)
$offEcho
$call.checkErrorLevel 'diff -bw concat.txt concatExpected.txt > %system.NullFile%'

$log test concatenateAll: True and outputDimensions: all
$onEmbeddedCode Connect:
- GDXReader:
    file: t.gdx
    readAll: True
- Projection:
    name: x.all(i,j)
    newName: xp(i,j)
- Projection:
    name: demand.l(j)
    newName: demand_level(j)
- Concatenate:
    outputDimensions: all
    concatenateAll: True
- GDXWriter:
    file: concat.gdx
    symbols:
        - name: setOutput
        - name: parameterOutput
$offEmbeddedCode
$call 'gdxdump concat.gdx > concat.txt'
$call 'gdxdump concat.gdx domainInfo >> concat.txt'
$onEcho > concatExpected.txt
$onEmpty

Set setOutput(*,*,*,*,*) /
'i'.'seattle'.'-'.'-'.'-', 
'i'.'san-diego'.'-'.'-'.'-', 
'j'.'new-york'.'-'.'-'.'-', 
'j'.'chicago'.'-'.'-'.'-', 
'j'.'topeka'.'-'.'-'.'-' /;

Parameter parameterOutput(*,*,*,*,*) /
'a'.'-'.'seattle'.'-'.'-' 350, 
'a'.'-'.'san-diego'.'-'.'-' 600, 
'b'.'-'.'-'.'new-york'.'-' 325, 
'b'.'-'.'-'.'chicago'.'-' 300, 
'b'.'-'.'-'.'topeka'.'-' 275, 
'd'.'-'.'seattle'.'new-york'.'-' 2.5, 
'd'.'-'.'seattle'.'chicago'.'-' 1.7, 
'd'.'-'.'seattle'.'topeka'.'-' 1.8, 
'd'.'-'.'san-diego'.'new-york'.'-' 2.5, 
'd'.'-'.'san-diego'.'chicago'.'-' 1.8, 
'd'.'-'.'san-diego'.'topeka'.'-' 1.4, 
'f'.'-'.'-'.'-'.'-' 90, 
'c'.'-'.'seattle'.'new-york'.'-' 0.225, 
'c'.'-'.'seattle'.'chicago'.'-' 0.153, 
'c'.'-'.'seattle'.'topeka'.'-' 0.162, 
'c'.'-'.'san-diego'.'new-york'.'-' 0.225, 
'c'.'-'.'san-diego'.'chicago'.'-' 0.162, 
'c'.'-'.'san-diego'.'topeka'.'-' 0.126, 
'xp'.'-'.'seattle'.'new-york'.'level' 50, 
'xp'.'-'.'seattle'.'new-york'.'upper' +Inf, 
'xp'.'-'.'seattle'.'new-york'.'scale' 1, 
'xp'.'-'.'seattle'.'chicago'.'level' 300, 
'xp'.'-'.'seattle'.'chicago'.'upper' +Inf, 
'xp'.'-'.'seattle'.'chicago'.'scale' 1, 
'xp'.'-'.'seattle'.'topeka'.'marginal' 0.036, 
'xp'.'-'.'seattle'.'topeka'.'upper' +Inf, 
'xp'.'-'.'seattle'.'topeka'.'scale' 1, 
'xp'.'-'.'san-diego'.'new-york'.'level' 275, 
'xp'.'-'.'san-diego'.'new-york'.'upper' +Inf, 
'xp'.'-'.'san-diego'.'new-york'.'scale' 1, 
'xp'.'-'.'san-diego'.'chicago'.'marginal' 0.00900000000000001, 
'xp'.'-'.'san-diego'.'chicago'.'upper' +Inf, 
'xp'.'-'.'san-diego'.'chicago'.'scale' 1, 
'xp'.'-'.'san-diego'.'topeka'.'level' 275, 
'xp'.'-'.'san-diego'.'topeka'.'upper' +Inf, 
'xp'.'-'.'san-diego'.'topeka'.'scale' 1, 
'demand_level'.'-'.'-'.'new-york'.'-' 325, 
'demand_level'.'-'.'-'.'chicago'.'-' 300, 
'demand_level'.'-'.'-'.'topeka'.'-' 275 /;

$offEmpty
SyNr  Type  DomInf Symbol
   2   Par Relaxed parameterOutput(symbols, *, i, j, attribute)
   1   Set Relaxed setOutput(symbols, *, i, j, attribute)
$offEcho
$call.checkErrorLevel 'diff -bw concat.txt concatExpected.txt > %system.NullFile%'

$log test outputDimensions
$onEmbeddedCode Connect:
- GDXReader:
    file: t.gdx
    readAll: True
- Concatenate:
    outputDimensions: [i,j]
    symbols:
        - name: a
        - name: b
        - name: f
        - name: c
        - name: d
- GDXWriter:
    file: concat.gdx
    symbols:
        - name: parameterOutput
$offEmbeddedCode

$call 'gdxdump concat.gdx > concat.txt'
$call 'gdxdump concat.gdx domainInfo >> concat.txt'
$onEcho > concatExpected.txt
$onEmpty

Parameter parameterOutput(*,*,*) /
'a'.'seattle'.'-' 350, 
'a'.'san-diego'.'-' 600, 
'b'.'-'.'new-york' 325, 
'b'.'-'.'chicago' 300, 
'b'.'-'.'topeka' 275, 
'f'.'-'.'-' 90, 
'c'.'seattle'.'new-york' 0.225, 
'c'.'seattle'.'chicago' 0.153, 
'c'.'seattle'.'topeka' 0.162, 
'c'.'san-diego'.'new-york' 0.225, 
'c'.'san-diego'.'chicago' 0.162, 
'c'.'san-diego'.'topeka' 0.126, 
'd'.'seattle'.'new-york' 2.5, 
'd'.'seattle'.'chicago' 1.7, 
'd'.'seattle'.'topeka' 1.8, 
'd'.'san-diego'.'new-york' 2.5, 
'd'.'san-diego'.'chicago' 1.8, 
'd'.'san-diego'.'topeka' 1.4 /;

$offEmpty
SyNr  Type  DomInf Symbol
   1   Par Relaxed parameterOutput(symbols, i, j)
$offEcho
$call.checkErrorLevel 'diff -bw concat.txt concatExpected.txt > %system.NullFile%'

$log test outputDimensions: all, dimensionMap and name with index space
$onEmbeddedCode Connect:
- GDXReader:
    file: t.gdx
    readAll: True
- Concatenate:
    outputDimensions: all
    dimensionMap: {i: ii, j: jj}
    symbols:
        - name: a(i1)
        - name: b
        - name: f
        - name: c(i3,i2)
        - name: d
- GDXWriter:
    file: concat.gdx
    symbols:
        - name: parameterOutput
$offEmbeddedCode
$call 'gdxdump concat.gdx > concat.txt'
$call 'gdxdump concat.gdx domainInfo >> concat.txt'
$onEcho > concatExpected.txt
$onEmpty

Parameter parameterOutput(*,*,*,*,*,*) /
'a'.'seattle'.'-'.'-'.'-'.'-' 350, 
'a'.'san-diego'.'-'.'-'.'-'.'-' 600, 
'b'.'-'.'new-york'.'-'.'-'.'-' 325, 
'b'.'-'.'chicago'.'-'.'-'.'-' 300, 
'b'.'-'.'topeka'.'-'.'-'.'-' 275, 
'f'.'-'.'-'.'-'.'-'.'-' 90, 
'c'.'-'.'-'.'seattle'.'new-york'.'-' 0.225, 
'c'.'-'.'-'.'seattle'.'chicago'.'-' 0.153, 
'c'.'-'.'-'.'seattle'.'topeka'.'-' 0.162, 
'c'.'-'.'-'.'san-diego'.'new-york'.'-' 0.225, 
'c'.'-'.'-'.'san-diego'.'chicago'.'-' 0.162, 
'c'.'-'.'-'.'san-diego'.'topeka'.'-' 0.126, 
'd'.'-'.'new-york'.'-'.'-'.'seattle' 2.5, 
'd'.'-'.'new-york'.'-'.'-'.'san-diego' 2.5, 
'd'.'-'.'chicago'.'-'.'-'.'seattle' 1.7, 
'd'.'-'.'chicago'.'-'.'-'.'san-diego' 1.8, 
'd'.'-'.'topeka'.'-'.'-'.'seattle' 1.8, 
'd'.'-'.'topeka'.'-'.'-'.'san-diego' 1.4 /;

$offEmpty
SyNr  Type  DomInf Symbol
   1   Par Relaxed parameterOutput(symbols, i1, jj, i3, i2, ii)
$offEcho
$call.checkErrorLevel 'diff -bw concat.txt concatExpected.txt > %system.NullFile%'

$log test outputDimensions, dimensionMap and name with index space
$onEmbeddedCode Connect:
- GDXReader:
    file: t.gdx
    readAll: True
- Concatenate:
    outputDimensions: [canning_plants, markets]
    dimensionMap: {i: canning_plants, j: markets}
    parameterName: pOutput
    symbols:
        - name: a
        - name: b(uni)
        - name: f
        - name: c
        - name: d
- GDXWriter:
    file: concat.gdx
    symbols:
        - name: pOutput
$offEmbeddedCode

$call 'gdxdump concat.gdx > concat.txt'
$call 'gdxdump concat.gdx domainInfo >> concat.txt'
$onEcho > concatExpected.txt
$onEmpty

Parameter pOutput(*,*,*,*) /
'a'.'seattle'.'-'.'-' 350, 
'a'.'san-diego'.'-'.'-' 600, 
'b'.'-'.'-'.'new-york' 325, 
'b'.'-'.'-'.'chicago' 300, 
'b'.'-'.'-'.'topeka' 275, 
'f'.'-'.'-'.'-' 90, 
'c'.'seattle'.'new-york'.'-' 0.225, 
'c'.'seattle'.'chicago'.'-' 0.153, 
'c'.'seattle'.'topeka'.'-' 0.162, 
'c'.'san-diego'.'new-york'.'-' 0.225, 
'c'.'san-diego'.'chicago'.'-' 0.162, 
'c'.'san-diego'.'topeka'.'-' 0.126, 
'd'.'seattle'.'new-york'.'-' 2.5, 
'd'.'seattle'.'chicago'.'-' 1.7, 
'd'.'seattle'.'topeka'.'-' 1.8, 
'd'.'san-diego'.'new-york'.'-' 2.5, 
'd'.'san-diego'.'chicago'.'-' 1.8, 
'd'.'san-diego'.'topeka'.'-' 1.4 /;

$offEmpty
SyNr  Type  DomInf Symbol
   1   Par Relaxed pOutput(symbols, canning_plants, markets, uni_0)
$offEcho
$call.checkErrorLevel 'diff -bw concat.txt concatExpected.txt > %system.NullFile%'

$log test concatenate symbol more than once
$onEmbeddedCode Connect:
- GDXReader:
    file: t.gdx
    readAll: True
- Concatenate:
    symbols:
        - name: a
        - name: d
          newName: d1
        - name: b
        - name: D
        - name: D(i1,j1)
          newName: d2
- GDXWriter:
    file: concat.gdx
    symbols:
        - name: parameterOutput
        - name: d
$offEmbeddedCode

$call 'gdxdump concat.gdx > concat.txt'
$call 'gdxdump concat.gdx domainInfo >> concat.txt'
$onEcho > concatExpected.txt
$onEmpty

Parameter d(*,*) distance in thousands of miles /
'seattle'.'new-york' 2.5, 
'seattle'.'chicago' 1.7, 
'seattle'.'topeka' 1.8, 
'san-diego'.'new-york' 2.5, 
'san-diego'.'chicago' 1.8, 
'san-diego'.'topeka' 1.4 /;

Parameter parameterOutput(*,*,*,*,*) /
'a'.'seattle'.'-'.'-'.'-' 350, 
'a'.'san-diego'.'-'.'-'.'-' 600, 
'd1'.'seattle'.'new-york'.'-'.'-' 2.5, 
'd1'.'seattle'.'chicago'.'-'.'-' 1.7, 
'd1'.'seattle'.'topeka'.'-'.'-' 1.8, 
'd1'.'san-diego'.'new-york'.'-'.'-' 2.5, 
'd1'.'san-diego'.'chicago'.'-'.'-' 1.8, 
'd1'.'san-diego'.'topeka'.'-'.'-' 1.4, 
'b'.'-'.'new-york'.'-'.'-' 325, 
'b'.'-'.'chicago'.'-'.'-' 300, 
'b'.'-'.'topeka'.'-'.'-' 275, 
'D'.'seattle'.'new-york'.'-'.'-' 2.5, 
'D'.'seattle'.'chicago'.'-'.'-' 1.7, 
'D'.'seattle'.'topeka'.'-'.'-' 1.8, 
'D'.'san-diego'.'new-york'.'-'.'-' 2.5, 
'D'.'san-diego'.'chicago'.'-'.'-' 1.8, 
'D'.'san-diego'.'topeka'.'-'.'-' 1.4, 
'd2'.'-'.'-'.'seattle'.'new-york' 2.5, 
'd2'.'-'.'-'.'seattle'.'chicago' 1.7, 
'd2'.'-'.'-'.'seattle'.'topeka' 1.8, 
'd2'.'-'.'-'.'san-diego'.'new-york' 2.5, 
'd2'.'-'.'-'.'san-diego'.'chicago' 1.8, 
'd2'.'-'.'-'.'san-diego'.'topeka' 1.4 /;

$offEmpty
SyNr  Type  DomInf Symbol
   1   Par Relaxed d(i, j)
   2   Par Relaxed parameterOutput(symbols, i, j, i1, j1)
$offEcho
$call.checkErrorLevel 'diff -bw concat.txt concatExpected.txt > %system.NullFile%'


$log test skip set
$onEmbeddedCode Connect:
- GDXReader:
    file: t.gdx
    readAll: True
- Concatenate:
    concatenateAll: True
    skip: set
- GDXWriter:
    file: concat.gdx
    symbols:
        - name: parameterOutput
$offEmbeddedCode

$call 'gdxdump concat.gdx > concat.txt'
$call 'gdxdump concat.gdx domainInfo >> concat.txt'
$onEcho > concatExpected.txt
$onEmpty

Parameter parameterOutput(*,*,*) /
'a'.'seattle'.'-' 350, 
'a'.'san-diego'.'-' 600, 
'b'.'-'.'new-york' 325, 
'b'.'-'.'chicago' 300, 
'b'.'-'.'topeka' 275, 
'd'.'seattle'.'new-york' 2.5, 
'd'.'seattle'.'chicago' 1.7, 
'd'.'seattle'.'topeka' 1.8, 
'd'.'san-diego'.'new-york' 2.5, 
'd'.'san-diego'.'chicago' 1.8, 
'd'.'san-diego'.'topeka' 1.4, 
'f'.'-'.'-' 90, 
'c'.'seattle'.'new-york' 0.225, 
'c'.'seattle'.'chicago' 0.153, 
'c'.'seattle'.'topeka' 0.162, 
'c'.'san-diego'.'new-york' 0.225, 
'c'.'san-diego'.'chicago' 0.162, 
'c'.'san-diego'.'topeka' 0.126 /;

$offEmpty
SyNr  Type  DomInf Symbol
   1   Par Relaxed parameterOutput(symbols, i, j)
$offEcho
$call.checkErrorLevel 'diff -bw concat.txt concatExpected.txt > %system.NullFile%'


$log test skip par
$onEmbeddedCode Connect:
- GDXReader:
    file: t.gdx
    readAll: True
- Concatenate:
    concatenateAll: True
    skip: par
- GDXWriter:
    file: concat.gdx
    symbols:
        - name: setOutput
$offEmbeddedCode

$call 'gdxdump concat.gdx > concat.txt'
$call 'gdxdump concat.gdx domainInfo >> concat.txt'
$onEcho > concatExpected.txt
$onEmpty

Set setOutput(*,*) /
'i'.'seattle', 
'i'.'san-diego', 
'j'.'new-york', 
'j'.'chicago', 
'j'.'topeka' /;

$offEmpty
SyNr  Type  DomInf Symbol
   1   Set Relaxed setOutput(symbols, *)
$offEcho
$call.checkErrorLevel 'diff -bw concat.txt concatExpected.txt > %system.NullFile%'


$log test skip symbols dimension
$onembeddedCode Connect:
- GDXReader:
    file: t.gdx
    readAll: True
- Concatenate:
    concatenateAll: True
    symbolsDimension: False
- PythonCode:
    code: |
        data = connect.container["setOutput"].records.values.tolist()
        expected = [['seattle', '-', '-', ''],
                    ['san-diego', '-', '-', ''],
                    ['new-york', '-', '-', ''],
                    ['chicago', '-', '-', ''],
                    ['topeka', '-', '-', '']] 
        if data != expected:
            raise Exception("Unexpected Data")
            
        data = connect.container["parameterOutput"].records.values.tolist()
        expected = [['-', 'seattle', '-', 350.0],
                    ['-', 'san-diego', '-', 600.0],
                    ['-', '-', 'new-york', 325.0],
                    ['-', '-', 'chicago', 300.0],
                    ['-', '-', 'topeka', 275.0],
                    ['-', 'seattle', 'new-york', 2.5],
                    ['-', 'seattle', 'chicago', 1.7],
                    ['-', 'seattle', 'topeka', 1.8],
                    ['-', 'san-diego', 'new-york', 2.5],
                    ['-', 'san-diego', 'chicago', 1.8],
                    ['-', 'san-diego', 'topeka', 1.4],
                    ['-', '-', '-', 90.0],
                    ['-', 'seattle', 'new-york', 0.225],
                    ['-', 'seattle', 'chicago', 0.153],
                    ['-', 'seattle', 'topeka', 0.162],
                    ['-', 'san-diego', 'new-york', 0.225],
                    ['-', 'san-diego', 'chicago', 0.162],
                    ['-', 'san-diego', 'topeka', 0.126]]
        if data != expected:
            raise Exception("Unexpected Data")
$offembeddedCode


$onEcho > t.gms
Set ii(*) cities /
'i1', 
'i2', 
'i3', 
'i4', 
'i5', 
'i6', 
'i7', 
'i8', 
'i9', 
'i10', 
'i11', 
'i12', 
'i13', 
'i14', 
'i15', 
'i16', 
'i17' /;

Set i(ii) subset of cities /
'i1', 
'i2', 
'i3', 
'i4', 
'i5', 
'i6' /;

Alias (j, i);

Set t(*) tours /
't1', 
't2', 
't3', 
't4', 
't5', 
't6', 
't7', 
't8', 
't9', 
't10', 
't11', 
't12', 
't13', 
't14', 
't15', 
't16', 
't17' /;

Set cc(*) /
'c1', 
'c2', 
'c3', 
'c4', 
'c5', 
'c6', 
'c7', 
'c8', 
'c9', 
'c10', 
'c11', 
'c12', 
'c13', 
'c14', 
'c15', 
'c16', 
'c17', 
'c18', 
'c19', 
'c20', 
'c21', 
'c22', 
'c23', 
'c24', 
'c25', 
'c26', 
'c27', 
'c28', 
'c29', 
'c30', 
'c31', 
'c32', 
'c33', 
'c34', 
'c35', 
'c36', 
'c37', 
'c38', 
'c39', 
'c40', 
'c41', 
'c42', 
'c43', 
'c44', 
'c45', 
'c46', 
'c47', 
'c48', 
'c49', 
'c50', 
'c51', 
'c52', 
'c53', 
'c54', 
'c55', 
'c56', 
'c57', 
'c58', 
'c59', 
'c60', 
'c61', 
'c62', 
'c63', 
'c64', 
'c65', 
'c66', 
'c67', 
'c68', 
'c69', 
'c70', 
'c71', 
'c72', 
'c73', 
'c74', 
'c75', 
'c76', 
'c77', 
'c78', 
'c79', 
'c80', 
'c81', 
'c82', 
'c83', 
'c84', 
'c85', 
'c86', 
'c87', 
'c88', 
'c89', 
'c90', 
'c91', 
'c92', 
'c93', 
'c94', 
'c95', 
'c96', 
'c97', 
'c98', 
'c99', 
'c100' /;

Parameter tour(i,j,t) subtours /
'i1'.'i6'.'t1' 1, 
'i2'.'i3'.'t3' 1, 
'i3'.'i2'.'t3' 1, 
'i4'.'i5'.'t2' 1, 
'i5'.'i4'.'t2' 1, 
'i6'.'i1'.'t1' 1 /;

Parameter cutcoeff(cc,i,j) /
'c1'.'i1'.'i6' 1, 
'c1'.'i2'.'i3' 1, 
'c1'.'i3'.'i2' 1, 
'c1'.'i4'.'i5' 1, 
'c1'.'i5'.'i4' 1, 
'c1'.'i6'.'i1' 1, 
'c2'.'i1'.'i3' 1, 
'c2'.'i2'.'i1' 1, 
'c2'.'i3'.'i2' 1, 
'c2'.'i4'.'i5' 1, 
'c2'.'i5'.'i6' 1, 
'c2'.'i6'.'i4' 1, 
'c3'.'i1'.'i3' 1, 
'c3'.'i2'.'i1' 1, 
'c3'.'i3'.'i2' 1, 
'c3'.'i4'.'i6' 1, 
'c3'.'i5'.'i4' 1, 
'c3'.'i6'.'i5' 1, 
'c4'.'i1'.'i2' 1, 
'c4'.'i2'.'i3' 1, 
'c4'.'i3'.'i1' 1, 
'c4'.'i4'.'i5' 1, 
'c4'.'i5'.'i6' 1, 
'c4'.'i6'.'i4' 1, 
'c5'.'i1'.'i2' 1, 
'c5'.'i2'.'i3' 1, 
'c5'.'i3'.'i1' 1, 
'c5'.'i4'.'i6' 1, 
'c5'.'i5'.'i4' 1, 
'c5'.'i6'.'i5' 1, 
'c6'.'i1'.'i6' 1, 
'c6'.'i2'.'i3' 1, 
'c6'.'i3'.'i1' 1, 
'c6'.'i4'.'i5' 1, 
'c6'.'i5'.'i4' 1, 
'c6'.'i6'.'i2' 1, 
'c7'.'i1'.'i3' 1, 
'c7'.'i2'.'i6' 1, 
'c7'.'i3'.'i2' 1, 
'c7'.'i4'.'i5' 1, 
'c7'.'i5'.'i4' 1, 
'c7'.'i6'.'i1' 1, 
'c8'.'i1'.'i3' 1, 
'c8'.'i2'.'i6' 1, 
'c8'.'i3'.'i1' 1, 
'c8'.'i4'.'i5' 1, 
'c8'.'i5'.'i4' 1, 
'c8'.'i6'.'i2' 1, 
'c9'.'i1'.'i2' 1, 
'c9'.'i2'.'i3' 1, 
'c9'.'i3'.'i6' 1, 
'c9'.'i4'.'i5' 1, 
'c9'.'i5'.'i4' 1, 
'c9'.'i6'.'i1' 1, 
'c10'.'i1'.'i3' 1, 
'c10'.'i2'.'i1' 1, 
'c10'.'i3'.'i6' 1, 
'c10'.'i4'.'i5' 1, 
'c10'.'i5'.'i4' 1, 
'c10'.'i6'.'i2' 1, 
'c11'.'i1'.'i6' 1, 
'c11'.'i2'.'i1' 1, 
'c11'.'i3'.'i2' 1, 
'c11'.'i4'.'i5' 1, 
'c11'.'i5'.'i4' 1, 
'c11'.'i6'.'i3' 1, 
'c12'.'i1'.'i2' 1, 
'c12'.'i2'.'i6' 1, 
'c12'.'i3'.'i1' 1, 
'c12'.'i4'.'i5' 1, 
'c12'.'i5'.'i4' 1, 
'c12'.'i6'.'i3' 1, 
'c13'.'i1'.'i5' 1, 
'c13'.'i2'.'i3' 1, 
'c13'.'i3'.'i2' 1, 
'c13'.'i4'.'i6' 1, 
'c13'.'i5'.'i4' 1, 
'c13'.'i6'.'i1' 1, 
'c14'.'i1'.'i6' 1, 
'c14'.'i2'.'i3' 1, 
'c14'.'i3'.'i2' 1, 
'c14'.'i4'.'i1' 1, 
'c14'.'i5'.'i4' 1, 
'c14'.'i6'.'i5' 1, 
'c15'.'i1'.'i4' 1, 
'c15'.'i2'.'i3' 1, 
'c15'.'i3'.'i2' 1, 
'c15'.'i4'.'i5' 1, 
'c15'.'i5'.'i6' 1, 
'c15'.'i6'.'i1' 1, 
'c16'.'i1'.'i6' 1, 
'c16'.'i2'.'i3' 1, 
'c16'.'i3'.'i2' 1, 
'c16'.'i4'.'i5' 1, 
'c16'.'i5'.'i1' 1, 
'c16'.'i6'.'i4' 1 /;

Parameter empty(i);
$offEcho
$call.checkErrorLevel gams t.gms lo=%gams.lo% a=c gdx=t.gdx

$log test name with index space
$onEmbeddedCode Connect:
- GDXReader:
    file: t.gdx
    readAll: True
- Concatenate:
    outputDimensions: [i, j, j]
    symbols:
        - name: tour(i,i,t)
        - name: cutcoeff(cc,j,j)
- GDXWriter:
    file: concat.gdx
    symbols:
        - name: parameterOutput
$offEmbeddedCode

$call 'gdxdump concat.gdx > concat.txt'
$call 'gdxdump concat.gdx domainInfo >> concat.txt'
$onEcho > concatExpected.txt
$onEmpty

Parameter parameterOutput(*,*,*,*,*,*) /
'tour'.'i1'.'-'.'-'.'i6'.'t1' 1, 
'tour'.'i2'.'-'.'-'.'i3'.'t3' 1, 
'tour'.'i3'.'-'.'-'.'i2'.'t3' 1, 
'tour'.'i4'.'-'.'-'.'i5'.'t2' 1, 
'tour'.'i5'.'-'.'-'.'i4'.'t2' 1, 
'tour'.'i6'.'-'.'-'.'i1'.'t1' 1, 
'cutcoeff'.'-'.'i1'.'i2'.'c4'.'-' 1, 
'cutcoeff'.'-'.'i1'.'i2'.'c5'.'-' 1, 
'cutcoeff'.'-'.'i1'.'i2'.'c9'.'-' 1, 
'cutcoeff'.'-'.'i1'.'i2'.'c12'.'-' 1, 
'cutcoeff'.'-'.'i1'.'i3'.'c2'.'-' 1, 
'cutcoeff'.'-'.'i1'.'i3'.'c3'.'-' 1, 
'cutcoeff'.'-'.'i1'.'i3'.'c7'.'-' 1, 
'cutcoeff'.'-'.'i1'.'i3'.'c8'.'-' 1, 
'cutcoeff'.'-'.'i1'.'i3'.'c10'.'-' 1, 
'cutcoeff'.'-'.'i1'.'i4'.'c15'.'-' 1, 
'cutcoeff'.'-'.'i1'.'i5'.'c13'.'-' 1, 
'cutcoeff'.'-'.'i1'.'i6'.'c1'.'-' 1, 
'cutcoeff'.'-'.'i1'.'i6'.'c6'.'-' 1, 
'cutcoeff'.'-'.'i1'.'i6'.'c11'.'-' 1, 
'cutcoeff'.'-'.'i1'.'i6'.'c14'.'-' 1, 
'cutcoeff'.'-'.'i1'.'i6'.'c16'.'-' 1, 
'cutcoeff'.'-'.'i2'.'i1'.'c2'.'-' 1, 
'cutcoeff'.'-'.'i2'.'i1'.'c3'.'-' 1, 
'cutcoeff'.'-'.'i2'.'i1'.'c10'.'-' 1, 
'cutcoeff'.'-'.'i2'.'i1'.'c11'.'-' 1, 
'cutcoeff'.'-'.'i2'.'i3'.'c1'.'-' 1, 
'cutcoeff'.'-'.'i2'.'i3'.'c4'.'-' 1, 
'cutcoeff'.'-'.'i2'.'i3'.'c5'.'-' 1, 
'cutcoeff'.'-'.'i2'.'i3'.'c6'.'-' 1, 
'cutcoeff'.'-'.'i2'.'i3'.'c9'.'-' 1, 
'cutcoeff'.'-'.'i2'.'i3'.'c13'.'-' 1, 
'cutcoeff'.'-'.'i2'.'i3'.'c14'.'-' 1, 
'cutcoeff'.'-'.'i2'.'i3'.'c15'.'-' 1, 
'cutcoeff'.'-'.'i2'.'i3'.'c16'.'-' 1, 
'cutcoeff'.'-'.'i2'.'i6'.'c7'.'-' 1, 
'cutcoeff'.'-'.'i2'.'i6'.'c8'.'-' 1, 
'cutcoeff'.'-'.'i2'.'i6'.'c12'.'-' 1, 
'cutcoeff'.'-'.'i3'.'i1'.'c4'.'-' 1, 
'cutcoeff'.'-'.'i3'.'i1'.'c5'.'-' 1, 
'cutcoeff'.'-'.'i3'.'i1'.'c6'.'-' 1, 
'cutcoeff'.'-'.'i3'.'i1'.'c8'.'-' 1, 
'cutcoeff'.'-'.'i3'.'i1'.'c12'.'-' 1, 
'cutcoeff'.'-'.'i3'.'i2'.'c1'.'-' 1, 
'cutcoeff'.'-'.'i3'.'i2'.'c2'.'-' 1, 
'cutcoeff'.'-'.'i3'.'i2'.'c3'.'-' 1, 
'cutcoeff'.'-'.'i3'.'i2'.'c7'.'-' 1, 
'cutcoeff'.'-'.'i3'.'i2'.'c11'.'-' 1, 
'cutcoeff'.'-'.'i3'.'i2'.'c13'.'-' 1, 
'cutcoeff'.'-'.'i3'.'i2'.'c14'.'-' 1, 
'cutcoeff'.'-'.'i3'.'i2'.'c15'.'-' 1, 
'cutcoeff'.'-'.'i3'.'i2'.'c16'.'-' 1, 
'cutcoeff'.'-'.'i3'.'i6'.'c9'.'-' 1, 
'cutcoeff'.'-'.'i3'.'i6'.'c10'.'-' 1, 
'cutcoeff'.'-'.'i4'.'i1'.'c14'.'-' 1, 
'cutcoeff'.'-'.'i4'.'i5'.'c1'.'-' 1, 
'cutcoeff'.'-'.'i4'.'i5'.'c2'.'-' 1, 
'cutcoeff'.'-'.'i4'.'i5'.'c4'.'-' 1, 
'cutcoeff'.'-'.'i4'.'i5'.'c6'.'-' 1, 
'cutcoeff'.'-'.'i4'.'i5'.'c7'.'-' 1, 
'cutcoeff'.'-'.'i4'.'i5'.'c8'.'-' 1, 
'cutcoeff'.'-'.'i4'.'i5'.'c9'.'-' 1, 
'cutcoeff'.'-'.'i4'.'i5'.'c10'.'-' 1, 
'cutcoeff'.'-'.'i4'.'i5'.'c11'.'-' 1, 
'cutcoeff'.'-'.'i4'.'i5'.'c12'.'-' 1, 
'cutcoeff'.'-'.'i4'.'i5'.'c15'.'-' 1, 
'cutcoeff'.'-'.'i4'.'i5'.'c16'.'-' 1, 
'cutcoeff'.'-'.'i4'.'i6'.'c3'.'-' 1, 
'cutcoeff'.'-'.'i4'.'i6'.'c5'.'-' 1, 
'cutcoeff'.'-'.'i4'.'i6'.'c13'.'-' 1, 
'cutcoeff'.'-'.'i5'.'i1'.'c16'.'-' 1, 
'cutcoeff'.'-'.'i5'.'i4'.'c1'.'-' 1, 
'cutcoeff'.'-'.'i5'.'i4'.'c3'.'-' 1, 
'cutcoeff'.'-'.'i5'.'i4'.'c5'.'-' 1, 
'cutcoeff'.'-'.'i5'.'i4'.'c6'.'-' 1, 
'cutcoeff'.'-'.'i5'.'i4'.'c7'.'-' 1, 
'cutcoeff'.'-'.'i5'.'i4'.'c8'.'-' 1, 
'cutcoeff'.'-'.'i5'.'i4'.'c9'.'-' 1, 
'cutcoeff'.'-'.'i5'.'i4'.'c10'.'-' 1, 
'cutcoeff'.'-'.'i5'.'i4'.'c11'.'-' 1, 
'cutcoeff'.'-'.'i5'.'i4'.'c12'.'-' 1, 
'cutcoeff'.'-'.'i5'.'i4'.'c13'.'-' 1, 
'cutcoeff'.'-'.'i5'.'i4'.'c14'.'-' 1, 
'cutcoeff'.'-'.'i5'.'i6'.'c2'.'-' 1, 
'cutcoeff'.'-'.'i5'.'i6'.'c4'.'-' 1, 
'cutcoeff'.'-'.'i5'.'i6'.'c15'.'-' 1, 
'cutcoeff'.'-'.'i6'.'i1'.'c1'.'-' 1, 
'cutcoeff'.'-'.'i6'.'i1'.'c7'.'-' 1, 
'cutcoeff'.'-'.'i6'.'i1'.'c9'.'-' 1, 
'cutcoeff'.'-'.'i6'.'i1'.'c13'.'-' 1, 
'cutcoeff'.'-'.'i6'.'i1'.'c15'.'-' 1, 
'cutcoeff'.'-'.'i6'.'i2'.'c6'.'-' 1, 
'cutcoeff'.'-'.'i6'.'i2'.'c8'.'-' 1, 
'cutcoeff'.'-'.'i6'.'i2'.'c10'.'-' 1, 
'cutcoeff'.'-'.'i6'.'i3'.'c11'.'-' 1, 
'cutcoeff'.'-'.'i6'.'i3'.'c12'.'-' 1, 
'cutcoeff'.'-'.'i6'.'i4'.'c2'.'-' 1, 
'cutcoeff'.'-'.'i6'.'i4'.'c4'.'-' 1, 
'cutcoeff'.'-'.'i6'.'i4'.'c16'.'-' 1, 
'cutcoeff'.'-'.'i6'.'i5'.'c3'.'-' 1, 
'cutcoeff'.'-'.'i6'.'i5'.'c5'.'-' 1, 
'cutcoeff'.'-'.'i6'.'i5'.'c14'.'-' 1 /;

$offEmpty
SyNr  Type  DomInf Symbol
   1   Par Relaxed parameterOutput(symbols, i, j, j, uni_0, uni_1)
$offEcho
$call.checkErrorLevel 'diff -bw concat.txt concatExpected.txt > %system.NullFile%'

$log test outputDimensions: all and name with index space
$onEmbeddedCode Connect:
- GDXReader:
    file: t.gdx
    readAll: True
- Concatenate:
    symbols:
        - name: tour(i,j,t)
        - name: cutcoeff(cc,j,j)
- GDXWriter:
    file: concat.gdx
    symbols:
        - name: parameterOutput
$offEmbeddedCode

$call 'gdxdump concat.gdx > concat.txt'
$call 'gdxdump concat.gdx domainInfo >> concat.txt'
$onEcho > concatExpected.txt
$onEmpty

Parameter parameterOutput(*,*,*,*,*,*) /
'tour'.'i1'.'i6'.'t1'.'-'.'-' 1, 
'tour'.'i2'.'i3'.'t3'.'-'.'-' 1, 
'tour'.'i3'.'i2'.'t3'.'-'.'-' 1, 
'tour'.'i4'.'i5'.'t2'.'-'.'-' 1, 
'tour'.'i5'.'i4'.'t2'.'-'.'-' 1, 
'tour'.'i6'.'i1'.'t1'.'-'.'-' 1, 
'cutcoeff'.'-'.'i1'.'-'.'c1'.'i6' 1, 
'cutcoeff'.'-'.'i1'.'-'.'c2'.'i3' 1, 
'cutcoeff'.'-'.'i1'.'-'.'c3'.'i3' 1, 
'cutcoeff'.'-'.'i1'.'-'.'c4'.'i2' 1, 
'cutcoeff'.'-'.'i1'.'-'.'c5'.'i2' 1, 
'cutcoeff'.'-'.'i1'.'-'.'c6'.'i6' 1, 
'cutcoeff'.'-'.'i1'.'-'.'c7'.'i3' 1, 
'cutcoeff'.'-'.'i1'.'-'.'c8'.'i3' 1, 
'cutcoeff'.'-'.'i1'.'-'.'c9'.'i2' 1, 
'cutcoeff'.'-'.'i1'.'-'.'c10'.'i3' 1, 
'cutcoeff'.'-'.'i1'.'-'.'c11'.'i6' 1, 
'cutcoeff'.'-'.'i1'.'-'.'c12'.'i2' 1, 
'cutcoeff'.'-'.'i1'.'-'.'c13'.'i5' 1, 
'cutcoeff'.'-'.'i1'.'-'.'c14'.'i6' 1, 
'cutcoeff'.'-'.'i1'.'-'.'c15'.'i4' 1, 
'cutcoeff'.'-'.'i1'.'-'.'c16'.'i6' 1, 
'cutcoeff'.'-'.'i2'.'-'.'c1'.'i3' 1, 
'cutcoeff'.'-'.'i2'.'-'.'c2'.'i1' 1, 
'cutcoeff'.'-'.'i2'.'-'.'c3'.'i1' 1, 
'cutcoeff'.'-'.'i2'.'-'.'c4'.'i3' 1, 
'cutcoeff'.'-'.'i2'.'-'.'c5'.'i3' 1, 
'cutcoeff'.'-'.'i2'.'-'.'c6'.'i3' 1, 
'cutcoeff'.'-'.'i2'.'-'.'c7'.'i6' 1, 
'cutcoeff'.'-'.'i2'.'-'.'c8'.'i6' 1, 
'cutcoeff'.'-'.'i2'.'-'.'c9'.'i3' 1, 
'cutcoeff'.'-'.'i2'.'-'.'c10'.'i1' 1, 
'cutcoeff'.'-'.'i2'.'-'.'c11'.'i1' 1, 
'cutcoeff'.'-'.'i2'.'-'.'c12'.'i6' 1, 
'cutcoeff'.'-'.'i2'.'-'.'c13'.'i3' 1, 
'cutcoeff'.'-'.'i2'.'-'.'c14'.'i3' 1, 
'cutcoeff'.'-'.'i2'.'-'.'c15'.'i3' 1, 
'cutcoeff'.'-'.'i2'.'-'.'c16'.'i3' 1, 
'cutcoeff'.'-'.'i3'.'-'.'c1'.'i2' 1, 
'cutcoeff'.'-'.'i3'.'-'.'c2'.'i2' 1, 
'cutcoeff'.'-'.'i3'.'-'.'c3'.'i2' 1, 
'cutcoeff'.'-'.'i3'.'-'.'c4'.'i1' 1, 
'cutcoeff'.'-'.'i3'.'-'.'c5'.'i1' 1, 
'cutcoeff'.'-'.'i3'.'-'.'c6'.'i1' 1, 
'cutcoeff'.'-'.'i3'.'-'.'c7'.'i2' 1, 
'cutcoeff'.'-'.'i3'.'-'.'c8'.'i1' 1, 
'cutcoeff'.'-'.'i3'.'-'.'c9'.'i6' 1, 
'cutcoeff'.'-'.'i3'.'-'.'c10'.'i6' 1, 
'cutcoeff'.'-'.'i3'.'-'.'c11'.'i2' 1, 
'cutcoeff'.'-'.'i3'.'-'.'c12'.'i1' 1, 
'cutcoeff'.'-'.'i3'.'-'.'c13'.'i2' 1, 
'cutcoeff'.'-'.'i3'.'-'.'c14'.'i2' 1, 
'cutcoeff'.'-'.'i3'.'-'.'c15'.'i2' 1, 
'cutcoeff'.'-'.'i3'.'-'.'c16'.'i2' 1, 
'cutcoeff'.'-'.'i4'.'-'.'c1'.'i5' 1, 
'cutcoeff'.'-'.'i4'.'-'.'c2'.'i5' 1, 
'cutcoeff'.'-'.'i4'.'-'.'c3'.'i6' 1, 
'cutcoeff'.'-'.'i4'.'-'.'c4'.'i5' 1, 
'cutcoeff'.'-'.'i4'.'-'.'c5'.'i6' 1, 
'cutcoeff'.'-'.'i4'.'-'.'c6'.'i5' 1, 
'cutcoeff'.'-'.'i4'.'-'.'c7'.'i5' 1, 
'cutcoeff'.'-'.'i4'.'-'.'c8'.'i5' 1, 
'cutcoeff'.'-'.'i4'.'-'.'c9'.'i5' 1, 
'cutcoeff'.'-'.'i4'.'-'.'c10'.'i5' 1, 
'cutcoeff'.'-'.'i4'.'-'.'c11'.'i5' 1, 
'cutcoeff'.'-'.'i4'.'-'.'c12'.'i5' 1, 
'cutcoeff'.'-'.'i4'.'-'.'c13'.'i6' 1, 
'cutcoeff'.'-'.'i4'.'-'.'c14'.'i1' 1, 
'cutcoeff'.'-'.'i4'.'-'.'c15'.'i5' 1, 
'cutcoeff'.'-'.'i4'.'-'.'c16'.'i5' 1, 
'cutcoeff'.'-'.'i5'.'-'.'c1'.'i4' 1, 
'cutcoeff'.'-'.'i5'.'-'.'c2'.'i6' 1, 
'cutcoeff'.'-'.'i5'.'-'.'c3'.'i4' 1, 
'cutcoeff'.'-'.'i5'.'-'.'c4'.'i6' 1, 
'cutcoeff'.'-'.'i5'.'-'.'c5'.'i4' 1, 
'cutcoeff'.'-'.'i5'.'-'.'c6'.'i4' 1, 
'cutcoeff'.'-'.'i5'.'-'.'c7'.'i4' 1, 
'cutcoeff'.'-'.'i5'.'-'.'c8'.'i4' 1, 
'cutcoeff'.'-'.'i5'.'-'.'c9'.'i4' 1, 
'cutcoeff'.'-'.'i5'.'-'.'c10'.'i4' 1, 
'cutcoeff'.'-'.'i5'.'-'.'c11'.'i4' 1, 
'cutcoeff'.'-'.'i5'.'-'.'c12'.'i4' 1, 
'cutcoeff'.'-'.'i5'.'-'.'c13'.'i4' 1, 
'cutcoeff'.'-'.'i5'.'-'.'c14'.'i4' 1, 
'cutcoeff'.'-'.'i5'.'-'.'c15'.'i6' 1, 
'cutcoeff'.'-'.'i5'.'-'.'c16'.'i1' 1, 
'cutcoeff'.'-'.'i6'.'-'.'c1'.'i1' 1, 
'cutcoeff'.'-'.'i6'.'-'.'c2'.'i4' 1, 
'cutcoeff'.'-'.'i6'.'-'.'c3'.'i5' 1, 
'cutcoeff'.'-'.'i6'.'-'.'c4'.'i4' 1, 
'cutcoeff'.'-'.'i6'.'-'.'c5'.'i5' 1, 
'cutcoeff'.'-'.'i6'.'-'.'c6'.'i2' 1, 
'cutcoeff'.'-'.'i6'.'-'.'c7'.'i1' 1, 
'cutcoeff'.'-'.'i6'.'-'.'c8'.'i2' 1, 
'cutcoeff'.'-'.'i6'.'-'.'c9'.'i1' 1, 
'cutcoeff'.'-'.'i6'.'-'.'c10'.'i2' 1, 
'cutcoeff'.'-'.'i6'.'-'.'c11'.'i3' 1, 
'cutcoeff'.'-'.'i6'.'-'.'c12'.'i3' 1, 
'cutcoeff'.'-'.'i6'.'-'.'c13'.'i1' 1, 
'cutcoeff'.'-'.'i6'.'-'.'c14'.'i5' 1, 
'cutcoeff'.'-'.'i6'.'-'.'c15'.'i1' 1, 
'cutcoeff'.'-'.'i6'.'-'.'c16'.'i4' 1 /;

$offEmpty
SyNr  Type  DomInf Symbol
   1   Par Relaxed parameterOutput(symbols, i, j, t, cc, j)
$offEcho
$call.checkErrorLevel 'diff -bw concat.txt concatExpected.txt > %system.NullFile%'

$log test empty symbol and emptyUel
$onEmbeddedCode Connect:
- GDXReader:
    file: t.gdx
    readAll: True
- Concatenate:
    outputDimensions: [i, j, k]
    emptyUel: " "
    symbols:
        - name: tour
        - name: empty
- GDXWriter:
    file: concat.gdx
    symbols:
        - name: parameterOutput
$offEmbeddedCode

$call 'gdxdump concat.gdx > concat.txt'
$call 'gdxdump concat.gdx domainInfo >> concat.txt'
$onEcho > concatExpected.txt
$onEmpty

Parameter parameterOutput(*,*,*,*,*) /
'tour'.'i1'.'i6'.''.'t1' 1, 
'tour'.'i2'.'i3'.''.'t3' 1, 
'tour'.'i3'.'i2'.''.'t3' 1, 
'tour'.'i4'.'i5'.''.'t2' 1, 
'tour'.'i5'.'i4'.''.'t2' 1, 
'tour'.'i6'.'i1'.''.'t1' 1 /;

$offEmpty
SyNr  Type  DomInf Symbol
   1   Par Relaxed parameterOutput(symbols, i, j, k, uni_0)
$offEcho
$call.checkErrorLevel 'diff -bw concat.txt concatExpected.txt > %system.NullFile%'

$log test order of outputDimensions with outputDimensions: all
$onEcho > t.gms
Sets
   i(i) / i0*i5 "i_text" /
   j(j) / j0*j5 "j_text" /
   k(k) / k0*k5 "k_text" /;
Alias (j,jj);
Parameters
   p1(k,j)
   p2(j,i,j); 
p1(k,j)$(uniform(0,1)>0.5) = uniform(0,1);
p2(j,i,j)$(uniform(0,1)>0.5) = uniform(0,1);

$onUNDF
Parameter special1 /'NA' NA, 'UNDF' UNDF/
          special2 /'NA' NA, '1' 1/;
$offEcho
$call.checkErrorLevel gams t.gms lo=%gams.lo% gdx=t.gdx

$onEmbeddedCode Connect:
- GDXReader:
    file: t.gdx
    symbols:
        - name: p1
        - name: p2
- Concatenate:
    concatenateAll: True
- GDXWriter:
    file: concat.gdx
    symbols:
      - name: parameterOutput
$offEmbeddedCode
$call 'gdxdump concat.gdx > concat.txt'
$call 'gdxdump concat.gdx domainInfo >> concat.txt'
$onEcho > concatExpected.txt
$onEmpty

Parameter parameterOutput(*,*,*,*,*) /
'p1'.'k0'.'j1'.'-'.'-' 0.550375356, 
'p1'.'k1'.'j0'.'-'.'-' 0.067113723, 
'p1'.'k1'.'j1'.'-'.'-' 0.998117627, 
'p1'.'k1'.'j2'.'-'.'-' 0.991133039, 
'p1'.'k1'.'j3'.'-'.'-' 0.130692483, 
'p1'.'k1'.'j4'.'-'.'-' 0.159517864, 
'p1'.'k2'.'j0'.'-'.'-' 0.435356381, 
'p1'.'k2'.'j5'.'-'.'-' 0.830892812, 
'p1'.'k3'.'j1'.'-'.'-' 0.775857606, 
'p1'.'k3'.'j4'.'-'.'-' 0.160172762, 
'p1'.'k3'.'j5'.'-'.'-' 0.265114545, 
'p1'.'k4'.'j1'.'-'.'-' 0.722719071, 
'p1'.'k4'.'j2'.'-'.'-' 0.463797865, 
'p1'.'k5'.'j3'.'-'.'-' 0.560745547, 
'p1'.'k5'.'j4'.'-'.'-' 0.297805864, 
'p1'.'k5'.'j5'.'-'.'-' 0.755821674, 
'p2'.'-'.'j0'.'i0'.'j0' 0.283864198, 
'p2'.'-'.'j0'.'i3'.'j0' 0.545309498, 
'p2'.'-'.'j0'.'i5'.'j0' 0.072766998, 
'p2'.'-'.'j1'.'i1'.'j1' 0.750207669, 
'p2'.'-'.'j1'.'i4'.'j1' 0.621229984, 
'p2'.'-'.'j2'.'i4'.'j2' 0.379937906, 
'p2'.'-'.'j2'.'i5'.'j2' 0.300034258, 
'p2'.'-'.'j3'.'i1'.'j3' 0.069232463, 
'p2'.'-'.'j4'.'i5'.'j4' 0.993602205, 
'p2'.'-'.'j5'.'i2'.'j5' 0.396684142, 
'p2'.'-'.'j5'.'i3'.'j5' 0.11957773, 
'p2'.'-'.'j5'.'i4'.'j5' 0.055418475, 
'p2'.'-'.'j5'.'i5'.'j5' 0.05140711 /;

$offEmpty
SyNr  Type  DomInf Symbol
   1   Par Relaxed parameterOutput(symbols, k, j, i, j)
$offEcho
$call.checkErrorLevel 'diff -bw concat.txt concatExpected.txt > %system.NullFile%'

$onEmbeddedCode Connect:
- GDXReader:
    file: t.gdx
    symbols:
        - name: p1
        - name: special1
        - name: special2
- Concatenate:
    concatenateAll: True
- GDXWriter:
    file: concat.gdx
    symbols:
      - name: parameterOutput
$offEmbeddedCode
$call 'gdxdump concat.gdx > concat.txt'
$call 'gdxdump concat.gdx domainInfo >> concat.txt'
$onEcho > concatExpected.txt
$onEmpty

Parameter parameterOutput(*,*,*,*) /
'p1'.'k0'.'j1'.'-' 0.550375356, 
'p1'.'k1'.'j0'.'-' 0.067113723, 
'p1'.'k1'.'j1'.'-' 0.998117627, 
'p1'.'k1'.'j2'.'-' 0.991133039, 
'p1'.'k1'.'j3'.'-' 0.130692483, 
'p1'.'k1'.'j4'.'-' 0.159517864, 
'p1'.'k2'.'j0'.'-' 0.435356381, 
'p1'.'k2'.'j5'.'-' 0.830892812, 
'p1'.'k3'.'j1'.'-' 0.775857606, 
'p1'.'k3'.'j4'.'-' 0.160172762, 
'p1'.'k3'.'j5'.'-' 0.265114545, 
'p1'.'k4'.'j1'.'-' 0.722719071, 
'p1'.'k4'.'j2'.'-' 0.463797865, 
'p1'.'k5'.'j3'.'-' 0.560745547, 
'p1'.'k5'.'j4'.'-' 0.297805864, 
'p1'.'k5'.'j5'.'-' 0.755821674, 
'special1'.'-'.'-'.'NA' NA, 
'special1'.'-'.'-'.'UNDF' Undf, 
'special2'.'-'.'-'.'NA' NA, 
'special2'.'-'.'-'.'1' 1 /;

$offEmpty
SyNr  Type  DomInf Symbol
   1   Par Relaxed parameterOutput(symbols, k, j, *)
$offEcho
$call.checkErrorLevel 'diff -bw concat.txt concatExpected.txt > %system.NullFile%'

$log test pandas behavior with gt.specialValues.NA
$onEmbeddedCode Python:
import numpy as np
import pandas as pd
import struct

def test_nans(arr):
    special_nan = "fffffffffffffffe"
    boo = []
    for i in arr:
        boo.append(bytes(struct.pack(">d", i)).hex() == special_nan)
    return boo

special_nan = struct.unpack(">d", bytes.fromhex("fffffffffffffffe"))[0]

arr = [special_nan, float("nan")]
arr2 = [1.0, 1.0]
arr3 = [1, 1]
arr4 = [special_nan, 1]

df1 = pd.DataFrame(arr)
df2 = pd.DataFrame(arr2)
df3 = pd.DataFrame(arr3)
df4 = pd.DataFrame(arr4)

# special nan not lost
if test_nans(pd.concat([df1, df2])[0])!=[True, False, False, False]:
    raise Exception("Expected special nan to NOT be lost.")

# special nan not lost
if test_nans(pd.concat([df1, df2, df4])[0])!=[True, False, False, False, True, False]:
    raise Exception("Expected special nan to NOT be lost.")

# special nan partially lost
if test_nans(pd.concat([df1, df3, df4])[0])!=[False, False, False, False, True, False]:
    raise Exception("Expected special nan to be partially lost.")

# special nan not lost
if test_nans(pd.concat([df1, df3])[0])!=[True, False, False, False]:
    raise Exception("Expected special nan to NOT be lost.")

# special nan not lost
if test_nans(pd.concat([df1, df3, df1])[0])!=[True, False, False, False, True, False]:
    raise Exception("Expected special nan to NOT be lost.")
    
# special nan assignment
df2.loc[0] = special_nan
if test_nans(df2[0])!=[False, False]:
    #[True, False] with pandas version < 1.5.0
    raise Exception("Exception with special nan assignment using loc/iloc.")
$offEmbeddedCode

$log test recover categories after pd.concat with and without symbols dimension
Set j /j1*j3/;
Alias (j,jj);
Parameter p1(*,*),p2(*,*);
p1(j,jj)=1;
p1(j,"j2")=0;
p1("j3","j2")=1;
p2(j,jj)=1;
p2(j,"j3")=0;
execute_unload "recover_categories.gdx", p1, p2;

EmbeddedCode Connect:
- GDXReader:
    file: recover_categories.gdx
- Concatenate:
    concatenateAll: True
- PythonCode:
    code: |
        dim3 = connect.container["parameterOutput"].getUELs(dimensions=2)
        if dim3 != ['j1', 'j2', 'j3', '-']:
            raise Exception("Unexpected categories.")
EndEmbeddedCode

EmbeddedCode Connect:
- GDXReader:
    file: recover_categories.gdx
- Concatenate:
    concatenateAll: True
    symbolsDimension: False
- PythonCode:
    code: |
        dim2 = connect.container["parameterOutput"].getUELs(dimensions=1)
        if dim2 != ['j1', 'j2', 'j3', '-']:
            raise Exception("Unexpected categories.")
EndEmbeddedCode

$log test behavior when input is None records symbol (Parameter)
EmbeddedCode Connect:
- PythonCode:
    code: |
      connect.container.addParameter("p", ["*", "i"])
- Concatenate:
    concatenateAll: True
- PythonCode:
    code: |
      data = connect.container['parameterOutput'].records
      expected_cols = ['symbols', 'uni', 'i', 'value']
      
      if data is None or not data.empty:
        raise Exception("Expected >parameterOutput< to have an empty DataFrame.")

      if (data.columns != expected_cols).any():
        raise Exception("Unexpected columns for >parameterOutput<.")
EndEmbeddedCode

$log test behavior when input is None records symbol (Set)
EmbeddedCode Connect:
- PythonCode:
    code: |
      connect.container.addSet("p", ["j", "*", "i"])
- Concatenate:
    concatenateAll: True
- PythonCode:
    code: |
      data = connect.container['setOutput'].records
      expected_cols = ['symbols', 'j', 'uni', 'i', 'element_text']
      
      if data is None or not data.empty:
        raise Exception("Expected >parameterOutput< to have an empty DataFrame.")

      if (data.columns != expected_cols).any():
        raise Exception("Unexpected columns for >parameterOutput<.")
EndEmbeddedCode