Create a static AIMMS Library from a runtime library

As you may know, runtime libraries offer enormous flexibility. However, there are situations whereby the same runtime library is generated over and over again. In these situations it is more efficient to generate the runtime library once and persist it. The persisting only needs to rerun, when there is a change in the input defining the runtime library.

An example use case of that is when the context in which the app runs now and then changes slightly, for instance a database schema that changes by adding/removing tables, and/or adding/removing columns in tables.

This article provides an example of generating and persisting such a library on the one hand, and using it in another application. In so doing, this article combines:

  • How databases can be queried for structure.

  • How runtime libraries can be used to generate code and persist code from such a structure.

  • How a DEX Client can be used to obtain a UUID.

  • How the put statement can be used to create a project.xml file.

The Story

In the database, occasionally table columns are added/removed/changed (type) to tables, or even tables are added/removed. To facilitate easy reading of these tables, identifiers are created as follows:

  • For a column that is a primary key,

    • a set is created using the same name, but prefixed with s_

    • an index is created using the same name, but prefixed with i_

  • For a column that is not a primary key,

    • a parameter is created using the same name, but prefixed with

      • p_ if the column at hand is a numerical column, and

      • sp_ otherwise.

    • In addition, the index domain consists of the indices made up from the primary key.

To avoid name clashes due to columns with the same name, but used in different tables, a module is created for every table.

A sample database table may look like:

../../_images/database-table-structure.png

Example generated code

The generated code for that table alone would be the following module:

 1Module modReadTableTableAB {
 2    Prefix: thisTableAB;
 3    DeclarationSection decls {
 4        Set s_NamesA {
 5            Index: i_NamesA;
 6        }
 7        Set s_NamesB {
 8            Index: i_NamesB;
 9        }
10        Parameter p_Vals1 {
11            IndexDomain: (i_NamesA, i_NamesB);
12        }
13        Parameter p_vals2 {
14            IndexDomain: (i_NamesA, i_NamesB);
15        }
16        StringParameter sp_vals3 {
17            IndexDomain: (i_NamesA, i_NamesB);
18        }
19        DatabaseTable db_TableAB {
20            DataSource: sp_connectionString;
21            TableName: "TableAB";
22            Mapping: {
23                "NamesA"-->i_NamesA,
24                "NamesB"-->i_NamesB,
25                "Vals1"-->p_Vals1(i_NamesA, i_NamesB),
26                "vals2"-->p_vals2(i_NamesA, i_NamesB),
27                "vals3"-->sp_vals3(i_NamesA, i_NamesB)
28            }
29        }
30    }
31    Procedure pr_readThis {
32        Body: {
33            read from table db_TableAB ;
34        }
35    }
36}

The download

Example download with AIMMS 4.92 apps

Once expanded, this example contains the following folders:

  1. data: a SQLite database and .dsn file.

  2. GenReadLib an AIMMS application that queries the database for structure in the data folder.

  3. libs a folder in which the generated libraries are placed.

  4. LeverageReadLib an AIMMS application that uses a generated library as one of its libraries.

Generating the runtime library

Generating the runtime library uses:

With that information available, generating the runtime library can be coded using model editing procedures. This is illustrated in the procedures in the section Generate Runtime Lib of the app GenReadLib.

More information about runtime libraries can be found at:

Differences between runtime libraries and static libraries

To take advantage of the differences between runtime libraries and static libraries, code for the following is generated as well:

  • Interface attribute. Here the identifiers declared in the Public Section are intended to be used from the outside, the contents of the interface attribute is Public_Section.

  • Use of initialization and termination procedures such as LibraryInitialization, LibraryPostInitialization, LibraryPreTermination, and LibraryTermination. They are typically not used in runtime libraries, but they are in static libraries. As they are not normally called from outside the library, they are put in a separate section within the Private Section of the library.

Persisting the library

To persist the library, the following functions are used:

Using the library

  • In the leveraging app, AIMMS MEnu > File > Library Manager you can add the Existing Library, by pointing to folder containing the library on your disk. In the example, it is located in the libs folder next to the folders for the generation and leveraging apps.

  • Direct use by name: In the app LeverageReadLib, the procedure MainExecution can directly reference an identifier in the generated static lib: drl::pr_readAll();