Using model tree structure information in your model

The tree structure of the model explorer in AIMMS allows you as a modeller to structure your project and make it easy to maintain a good overview. Especially if your model becomes larger, having a well structured model will allow you to quickly find the identifiers you need. For AIMMS, the structure and order of the tree are not important: if you want, you could even declare all your identifiers under one declaration section.

One of the nice things is that you can actually use the information from the tree structure in your model: each section or declaration section that you introduce in your model will automatically create a new set in AIMMS with the same name as the section. This new set is a subset of the predefined set AllIdentifiers and it will contain all identifiers that are declared under the section or declaration section.

Example of structured model tree

Example of structured model tree

Suppose that you have a model tree with the structure depicted on the right. This means that AIMMS will automatically create the following subsets of AllIdentifiers:

  • Input_Section
  • Set_declarations
  • Location_declarations
  • Transport_declarations
  • Output_Section

As you can see from the above list, AIMMS will convert the spaces in the names of the (declaration) sections into underscores. This conversion is done because identifiers in AIMMS cannot contain spaces.

From the above list, you can also see that no separate set is created for the declaration section “Declaration” under the section Output Section. The reason for this is that no two identifiers in AIMMS can have the same name. The only exception to this rule is declaration sections that can all share the name Declaration. This means that for declaration sections, AIMMS will only automatically create the subset of AllIdentifiers if it has a different name than the default name Declaration.

The set Set_declarations from the example above will only contain the element ‘Locations’. The set Input_Section will not only contain all the identifiers declared under it explicitly, but it will also contain the sets that are automatically created because of the (declaration) sections under it. This means that it will also contain the elements ‘Set_Declarations’, ‘Location_declarations’, and ‘Transport_declarations’.

Note that any of the indices declared with sets are seen as separate elements in the set. For example, the set Locations has three indices: loc, locFrom, and locTo. These three indices will be three separate elements in both the sets Input_Section and Set_declarations.

A typical example use for these automatically created sets is that you are able to empty specific parts of your model. For example, if you want to empty all the identifiers in your model that are related to input, you can do so with the following statement:

empty Input_Section ;

Similarly, with the write statement you can also write the contents of all identifiers declared under the given section to a file as follows:

write Input_Section to file "values_of_identifers_under_Input.txt" ;

If you want to see the exact contents of such a automatically created set, you can assign its contents to a set you declared in your model. Please keep in mind that you will have to declare this set to be a subset of AllIdentifiers. If you have such a subset of AllIdentifiers, e.g. mySubSet, you can use the following statement:

mySubSet := Input_Section ;

to assign the contents of the automatically created set to the set mySubset, after which you can inspect the data of mySubSet.

Posted in Advanced | Tagged , , | 2 Comments

Displaying line numbers in the editor of the AIMMS IDE

When you want to share some information about your model, you typically want to direct another person to take a look at specific lines in a procedure or a definition. In order to do this, you will need to know the specific line number. By default, the editor in the IDE of AIMMS will not show any line numbers in attributes that can be multi-line.

You can enable the display of line numbers in the editor settings, which you can access via Editor Settings… under the Settings menu. If you go to the Misc tab, you will see the following options:

AIMMS IDE Editor settings

AIMMS IDE Editor settings

By changing the value for the setting LineNumberMargin to True, AIMMS will display the line numbers for all the attributes that can consist of multiple lines. The result will look like the image below:

Line numbers displayed in multiple line attribute

Line numbers displayed in multiple line attribute

Jump to specific line number

Jump to specific line number by pressing Ctrl+g

After you have received a line number that is interesting, you can jump to a specific line number quickly by pressing the keyboard shortcut Ctrl+g. This will open the dialog depicted on the right.

Alternatively, you can open the same dialog via Goto Line… under the Edit menu.

Note that this Goto line function works regardless of whether the line numbers are displayed or not.

Posted in Beginner | Tagged , | Leave a comment

Quickly get text representation of one or more identifiers

When you need to share some identifiers with another person (e.g. on the AIMMS Google group or during contact with AIMMS Support), most of the times you can just copy the definition field of a parameter/variable/constraint. However, sometimes you must not only share the definition, but the values of all attributes, including the index domain/unit/etc.

Of course, you can manually copy all of these attributes to a separate text editor window, but this is a rather cumbersome approach. Another approach is to put the identifiers you want to have the text representation for in a separate section and use the information in the article Exporting a section and importing it in another AIMMS project to export this section to an .aim file. Unfortunately, this approach also requires quite some additional steps.

View selected identifiers as text

View selected identifiers as text

A much easier and faster approach is to make use of the Text Representation option under the View menu. To use this feature, just select an identifier in the model tree and under the View menu, select Text Representation > Selected Parts. Alternatively, you can also press the keyboard shortcut Ctrl+T after you have selected the identifier in your model. After you pressed this, AIMMS will open a new window/tab page containing the textual representation of the identifier selected. You can then copy these contents and share it with other people.

You can also select multiple identifiers in the model tree by pressing the Ctrl key while selecting the additional identifiers in the tree.

The resulting new tab page that is opened will look something like the image below:

Text representation of selected identifiers

Text representation of selected identifiers

Posted in Beginner | Tagged , | Leave a comment

Quickly expanding all identifiers in the model tree

As most AIMMS users will know (or maybe should know :) ), the position where you double-click on an identifier (i.e. the icon or the text) in the model tree leads to different outcomes. If you double-click on the name of the identifier, you will always open the attribute form for the selected identifier.

If you double-click on the icon of the identifier that supports child identifiers (e.g. Section, Declaration Section, etc.), AIMMS will open the identifier node in the tree and show the child identifiers. In case of double-clicking on the icon of an identifier that does not support an underlying sub-tree, AIMMS will just open the attribute form (e.g. double-clicking on the [P] icon of a parameter identifier will just open the attribute form of the parameter).

Quickly expand all sub-trees

Quickly expand all sub-trees

When AIMMS opens the identifier node in the tree, it will just show the first layer of child identifiers. This means that at each level, you will have to expand an identifier node to get to the final declarations.

One of the lesser known features of AIMMS is that you can quickly expand all sub-trees that are below a selected identifier (e.g. a Section identifier). You can do this by pressing the CTRL key on your keyboard while double-clicking the icon of the identifier that can contain a sub-tree (e.g. Section).

An example of this is shown in the picture on the right. Note that you can do this at any point in your model tree. All the identifiers that are not in the sub-tree of the currently selected identifier will stay as they were, only the complete sub-tree under the currently selected identifier is expanded. Holding the CTRL key while using the right cursor key on the keyboard will have the same result (i.e. expand all sub-trees below the currently selected identifier).

Quickly expand all sub-trees except declaration sections

Quickly expand all sub-trees except declaration sections

A second option is that you do not want to expand all sub-trees, but only those sub-trees that are not under a declaration section. One of the reasons for this could be that you only want to see the structure of your AIMMS project, but not all the individual declarations for sets and parameters.

You can do this in AIMMS by not pressing the CTRL key while double-clicking on the identifier icon (or using the right cursor key), but pressing the Shift key. The picture on the left will show the result after pressing the Shift key while double-clicking on the book-icon in front of Section 1.

Posted in Beginner | Tagged | Leave a comment

Little trick to call AIMMS API from within AIMMS

For an internal project I was working on, I had to determine whether a given procedure (provided by an element parameter in the predefined set AllProcedures) had a certain prototype (i.e. number/types of the arguments). In this particular case, I wanted to check whether the given procedure had exactly one argument, which was a string parameter with the Input property.

Recursion: See Recursion

Recursion: See Recursion

Unfortunately, within the AIMMS language there is no direct way of obtaining the number of arguments of a procedure or the type. Luckily, the AIMMS API does provide this functionality. One of the features of AIMMS is that you can call methods in a DLL by introducing external procedure identifiers in your AIMMS project. By introducing an external procedure that uses the libaimms.dll, you can actually call the AIMMS API functions directly from within your project again. So from within AIMMS, you call the AIMMS API again.

I think that for most of the API functions provided by the libaimms.dll it is not very useful if you call them from within AIMMS again via this way. However, one of the methods in the DLL is AimmsProcedureHandleCreate, which creates a handle to an AIMMS procedure in the project. When you call this method, you will also get some information about the number of arguments and the type of each of these arguments.

To be able to call the AimmsProcedureHandleCreate (and the corresponding AimmsProcedureHandleDelete to delete the handle again afterwards) method from the libaimms.dll, you have to introduce the following two external procedure in your AIMMS project:

EXTERNAL PROCEDURE
  identifier  :  AimmsProcedureHandleCreate
  arguments   :  (theProcedure,theHandle,nArgs,argType)
  dll name    :  "libaimms.dll"
  return type :  integer
  body call   :  AimmsProcedureHandleCreate(
                     scalar string : theProcedure,
                     scalar integer : theHandle,
                     scalar integer : nArgs,
                     array integer : argType
                   )
 
  DECLARATION SECTION 
 
    ELEMENT PARAMETER:
       identifier   :  theProcedure
       range        :  AllProcedures
       property     :  Input ;
 
    PARAMETER:
       identifier   :  theHandle
       property     :  Output ;
 
    PARAMETER:
       identifier   :  nArgs
       property     :  Output ;
 
    PARAMETER:
       identifier   :  argType
       index domain :  iArgType
       property     :  Output ;
 
    SET:
       identifier   :  sArgTypes
       index        :  iArgType ;
 
  ENDSECTION  ;
 
 
ENDPROCEDURE  ;
 
 
 
EXTERNAL PROCEDURE
  identifier  :  AimmsProcedureHandleDelete
  arguments   :  (theHandle)
  dll name    :  "libaimms.dll"
  return type :  integer
  body call   :  AimmsProcedureHandleDelete(
                     scalar integer : theHandle
                   )
 
  DECLARATION SECTION 
 
    PARAMETER:
       identifier :  theHandle
       property   :  Input ;
 
  ENDSECTION  ;
 
 
ENDPROCEDURE  ;

As you can see, the DLL that is used is the libaimms.dll. These two external procedures can then be used by one final procedure CheckProcedurePrototype that will check whether the procedure it gets as an argument has a certain prototype. The source of this procedure is the following:

PROCEDURE
  identifier :  CheckProcedurePrototype
  arguments  :  (theProcedure)
 
  DECLARATION SECTION
 
    PARAMETER:
       identifier   :  pProcHandle ;
 
    PARAMETER:
       identifier   :  pNumArgs ;
 
    SET:
       identifier   :  sProcArgs
       index        :  iProcArgs
       initial data :  !The maximum number of arguments we want to support
                       {0..512} ;
 
    PARAMETER:
       identifier   :  pProcArgType
       index domain :  (iProcArgs) ;
 
    PARAMETER:        
       identifier   :  pResult ;
 
    ELEMENT PARAMETER:
       identifier   :  theProcedure
       range        :  AllProcedures
       property     :  Input ;
 
  ENDSECTION  ; 
 
  body       :  
    !Create handle to the procedure. When calling the
    !API, we automatically get all the information about the
    !arguments of this procedure
    pResult := AimmsProcedureHandleCreate(
                    theProcedure :  theProcedure,
                    theHandle    :  pProcHandle,
                    nArgs        :  pNumArgs,
                    argType      :  pProcArgType ) ;
 
    if pResult then 
            !If the API call was successful, we must delete the handle
            AimmsProcedureHandleDelete(theHandle : pProcHandle ) ;
 
            !Now we can check the actual prototype. The meaning of the values
            !in the pProcArgType parameter, can be found in the libaimms.h
            !file in your AIMMS installation. The relevant parts are:
 
            !       #define AIMMSAPI_STORAGE_HANDLE  0x00000000
            !       #define AIMMSAPI_STORAGE_DOUBLE  0x00000001
            !       #define AIMMSAPI_STORAGE_INT     0x00000002
            !       #define AIMMSAPI_STORAGE_BINARY  0x00000003
            !       #define AIMMSAPI_STORAGE_STRING  0x00000004
            !
            !       #define AIMMSAPI_INPUT           0x00000010
            !       #define AIMMSAPI_OUTPUT          0x00000020
            !       #define AIMMSAPI_INPUT_OUTPUT    0x00000040
 
 
            !For example, we want 1argument and it must be a string parameter
            !that is input only. This means that we have to OR the value
            !0x04 (STORAGE_STRING) and 0x10 (INPUT) to get the value 0x14
            !0x14 (hex) => 20 (decimal)
            if pNumArgs = 1 and pProcArgType( first(iProcArgs) ) = 20 then
                    return 1 ;
            endif ;
    endif ;
 
    !If the API call was not successful, or the prototype of the
    !procedure was not correct, return the value 0
    return 0 ;
 
ENDPROCEDURE  ;

For more details about the AIMMS API and the above used methods, please take a look at the AIMMS documentation.

Dicslaimer: Though the above code works (and I had a smile on my face when I found this possibility :) ), I would like to point out that you have to be extremely careful when calling the AIMMS API from within AIMMS this way: very quickly, you can end up in unpredictable situations because of the locking mechanisms used.

You can download the source of the above (external) procedures from the link below:

Source file for CheckProcedurePrototype
Title : Source file for CheckProcedurePrototype
Caption : Source file for CheckProcedurePrototype
File name : CheckProcedurePrototype.aim
Size : 4 kB

Posted in Advanced | Tagged , , | Leave a comment

Using LoopCount instead of explicit counting parameter in loops

There are cases where you want to execute some set of statements in an AIMMS procedure a couple of times. If you want to execute the statements n times, the trivial (but not very smart) way would be to just copy the statements n times.

A better approach, which I guess is used most often, is to use a repetitive loop (for, while, repeat) and declare a new local parameter for this procedure that will be used to keep track of how many iterations have been done in the loop. To execute a block of statements n times, you will first have to initialize this counter parameter to 0 or 1 (depending on your preference to start counting at 0 or 1) and then use a while-loop with a termination criteria to execute the statements repetitively. Furthermore, you must also ensure that you increment the value of your local counter parameter with one in each iteration. So if you declare the additional parameter myLoopCounter, the required code will look like:

!Initialize the myLoopcounter to the value 1
myLoopCounter := 1 ; 
while myLoopcounter <= 3 do
    DialogMessage("Current iteration " + myLoopCounter ) ; 
    !And increment the counter by one
    myLoopCounter += 1 ; 
endwhile ;

An even easier approach (but probably far less known) that does not require you to declare any temporary local parameters, is to make use of the predefined LoopCount operator in AIMMS. With repetitive loops like while, for, and repeat, this LoopCount operator will automatically be incremented each time the loop is run. Using the LoopCount operator, the above code could be transformed into the following:

while LoopCount <= 3 do
	dialogMessage("Current iteration " + LoopCount) ; 
endwhile ;

If you have multiple nested loops, you can name each of these loops by using a loop string in the statement. You can access the value of a LoopCount corresponding to one particular of the nested loops by providing the loop string name as an argument to the LoopCount. If you do not provide any loop string, the LoopCount operator returns the value of the closest repetitive loop. If you run the example code below, you will see that when not providing a loop string, the value returned by the LoopCount operator is the same as the LoopCount for the inner-loop because this is the closest repetitive loop.

while LoopCount <= 3 do "outer-loop"
    while LoopCount <= 4 do "inner-loop" 
        dialogMessage( "Outer : " + LoopCount("outer-loop") 
                       + "\n"
                       + "Inner : " + LoopCount("inner-loop")
                       + "\n"
                       + "No string : " + LoopCount
                      ) ; 
    endwhile ; 
endwhile ;

Posted in Beginner | Tagged , | Leave a comment

Adding a custom splashscreen to your AIMMS application

Default splashscreen for AIMMS Developer

Default splashscreen for AIMMS Developer

After you are finished with creating your AIMMS application, you can deploy it to the people who will use your application. Instead of using the standard AIMMS splashscreen displayed on the right, you have the option to provide your own custom splashscreen.
Please note that the splashscreen depicted is the splashscreen of the developer version of AIMMS. If the user of your application has an AIMMS end-user license, the purple background color will actually be green.

Gate Assignment splashscreen

Gate Assignment splashscreen

You can instruct AIMMS to not display the standard splashscreen, but a custom one by creating a BMP file with the same name as the project file (i.e. the .prj file). If you open the Gate Assignment example from the index of all examples, you will see that splashscreen depicted on the left is.

The name of the .prj file of the gate assignment project is “Gate Assignment.prj”. By saving the above picture as “Gate Assignment.bmp” in the same folder as the “Gate Assignment.prj” file, AIMMS will now display the new splashscreen. Please note that you must use the bitmap (BMP) format, as AIMMS will only look for this extension (and not other image file formats).

Posted in Beginner | Tagged , | Leave a comment

Quick Win on AIMMS Data Page

AIMMS Data Page facilities directly view of the data associated with a particular identifier. With some clicks, drag & drops, a data page can also be quickly modified to display one or more identifiers in different formats.

A data page can be opened via the Data button, via the right mouse menu, or via shortcut key Ctrl + D for every global identifier.

Multi-dimensional parameters, variables and constraints are displayed in Pivot Table by default.  Using the Viewing Mode Switching Button button on the data page you can switch view among Pivot Table, Composite Table, Table, and Sparse List .  For example, the following is the Composite Table view of the 2-dimensional data “Transport” in the “Transport Model” example.

Composite Table View

On the above page, via the Selection Object on the top, you can select any given d (Depot) and c (Customer) to view the value.

If you want to add other identifiers to the same table, for example, adding “UnitTransportCost” to the above table, you can easily do so in three steps: 1. Switch the data page to “Edit” Mode; 2. select “UnitTransportCost” in the Model Explorer by mouse; 3. drag and drop “UnitTransportCost” to the table.

Drag UnitTransportCost

After mouse releases, you will see “UnitTransportCost” shows in the table.

Updated Table

You can add an identifier to other types of table in the same way. And in page Edit Mode, you can change other properties of the table in the table Properties Dialog, for example, adding or removing suffices, editing format, etc.

After the changes, you can save the modified data page. The saved data page will appear under All Data Pages section in the Page Manager.

Updated Data Page

Please note if a modified data page exists, which is with format “[Data Page] Identifier Name”,  AIMMS will use this page as the data page for that identifier. In order to view the default data page,  you need to hold down the Shift key while opening the data page, or remove the data page from the All Data Pages section.

Posted in Beginner | Leave a comment

Minimizing objective containing a min-operator

During the last couple of months I saw the exact same question from different customers, namely that they wanted to minimize an objective that contained a binary min operator. For example, the minimization objective contained the following term:

50 * min( aParameter, aVariable).

The idea of using this binary min operator was to introduce a ceiling to the contribution of a variable to the objective. Recently, I also saw a similar topic being discussed by Erwin Kalvelagen in his max tricks blog post.

If you want to keep your problem linear, you cannot make use of the min operator directly in a constraint, so you will have to work around it with some modelling. You can do this introducing a new variable min_param_var, that will be forced to have a value equal to the binary min-operator by using additional constraints. This new variable will replace the original “min( aParameter, aVariable)” term in the objective (and thus will have coefficient of 50 in objective in the above example).

Furthermore, we also need a new binary variable param_smaller_than_var, that will get the value 1 if the value of the parameter is smaller than the value of the variable and 0 otherwise.

Finally, we also need to add two constraints and a big-M to the model to ensure the newly introduced variables get the correct values. The value of the big-M should be a sufficiently large value, which in this particular case is max( aParameter, aVariable.upper ).

The 2 constraints you will have to add are:

  • \mathrm{min\_param\_var} \ge \mathrm{aParameter} * \mathrm{param\_smaller\_than\_var}
  • \mathrm{min\_param\_var} \ge \mathrm{aVariable} - \mathrm{param\_smaller\_than\_var} * M

If the variable min_param_var has a positive component in the objective, the solver will try to minimize the value of the variable min_param_var and the above constraints will ensure that the variable param_smaller_than_var will automatically get the value 1 if aParameter <= aVariable and 0 otherwise.

By filling in some values for the parameter and the variable in the above constraints, you can verify that the binary variable must indeed get the correct value to ensure that the min_param_var variable will get the smallest value possible.

Additional information: In case you are minimizing an objective that contains a binary max operator, you can use a similar approach. However, in this case you do not need the big-M, but only one additional variable max_param_var and two constraints:

  • \mathrm{max\_param\_var} \ge \mathrm{aParameter}
  • \mathrm{max\_param\_var} \ge \mathrm{aVariable}

Posted in Beginner | Tagged , | Leave a comment

Starting AimmsInterrupt tool from installation-free AIMMS

Screenshot AimmsInterrupt

Screenshot AimmsInterrupt

In some of the posts I have mentioned the AimmsInterrupt tool already. If you install a recent version of AIMMS, this tool will also be installed and is made available for starting via the Start Menu.

However, if you only make use of installation-free versions of AIMMS, nothing is added to the Start Menu, meaning there is no direct way to start the tool. Luckily, it is still possible to start the AimmsInterrupt tool from within AIMMS itself. If you start an installation-free version of AIMMS you can put the following statement in a procedure:

execute("c:\\Program Files\\Paragon Decision Technology\\Common\\Bin\\AimmsInterrupt.exe") ;

When you execute this procedure, the AimmsInterrupt tool will be started, from which you can now interrupt any of the AIMMS sessions that is running.

Posted in Beginner | Tagged , , | Leave a comment