embeddedSort.gms : Sorting of numerical data using the embedded code facility

Description

The embedded code facility allows to integrate external code (e.g. Python) during
both compile and execution time of a GAMS program. GAMS symbols are shared with
the external code, so no communication via disk is necessary.

This example demonstrates how to sort random numerical GAMS data in Python at
GAMS execution time.

Contributor: Lutz Westermann, July 2017


Category : GAMS Data Utilities library


Main file : embeddedSort.gms   includes :  embeddedSort.gms

$Title Sorting of numerical data using the embedded code facility

$ontext
The embedded code facility allows to integrate external code (e.g. Python) during
both compile and execution time of a GAMS program. GAMS symbols are shared with
the external code, so no communication via disk is necessary.

This example demonstrates how to sort random numerical GAMS data in Python at
GAMS execution time.

Contributor: Lutz Westermann, July 2017
$offtext


* On the major platforms, GMSPYTHONHOME gets set automatically, otherwise the user has to set it
* This condition can also be removed, if one has set up its Python environment appropriately
$escape &
$if "%sysenv.GMSPYTHONHOME%"=="%&sysenv.GMSPYTHONHOME%&" $abort.noError Embedded code Python not ready to be used


Set       i         / 1*10 /;
Parameter a(i)      Random Data
          aIndex(i) Sorted Index of a;

* Generate random data
a(i) = uniformInt(1,10*card(i));

* Embedded Python code:
* - GAMS parameter "a" is read from GAMS as a list
* - It gets sorted
* - The index position of the original data gets stored in "aIndex"
* - "AIndex" gets written back to GAMS
embeddedCode Python:
  a = list(gams.get("a"))

  tmp = [r[0] for r in sorted(enumerate(a), key=lambda x:x[1][-1])]
  aIndex = len(a)*[-1]
  for idx in range(len(tmp)):
      aIndex[tmp[idx]] = (a[tmp[idx]][0], idx+1)

  gams.set("aIndex",aIndex)
endEmbeddedCode aIndex

display a, aIndex;

********************************************************************************
* In some cases it might be expensive to initialize the embedded code
* environment. For this, it is possible to initialize it once, pause it's
* execution and continue after executing some GAMS statements


* Generate new random data
a(i) = uniformInt(1,10*card(i));

* Embedded Python code like above, just pause it at the end
embeddedCode Python:
  a = list(gams.get("a"))

  tmp = [r[0] for r in sorted(enumerate(a), key=lambda x:x[1][-1])]
  aIndex = len(a)*[-1]
  for idx in range(len(tmp)):
      aIndex[tmp[idx]] = (a[tmp[idx]][0], idx+1)

  gams.set("aIndex",aIndex)
pauseEmbeddedCode aIndex

Display a,aIndex;

* Generate new random data
a(i) = uniformInt(1,10*card(i));

* Embedded Python code like above, just continue it without reinitialization
continueEmbeddedCode:
  a = list(gams.get("a"))

  tmp = [r[0] for r in sorted(enumerate(a), key=lambda x:x[1][-1])]
  aIndex = len(a)*[-1]
  for idx in range(len(tmp)):
      aIndex[tmp[idx]] = (a[tmp[idx]][0], idx+1)

  gams.set("aIndex",aIndex)
endEmbeddedCode AIndex

Display a,aIndex;