Tech Blog

Tips and Tricks for AIMMS Users

Deploying a project with AIMMS as a self-contained solution

Deploy your project including AIMMS as a self-contained solution

Deploy your project including AIMMS as a self-contained solution

When you are finished with creating your project and want to deploy it in such a way that it requires as little steps from the end-user as possible, you can make use of our installation free version of AIMMS. One of the features in these installation free versions is that it will check if there exists a folder StartupProject in the same folder as the installation free executable. If this folder exists, AIMMS will automatically start the first project (.prj file) that it finds in this directory.

So you can deploy a self-contained solution (i.e. the required AIMMS executable and your project) to your end-users by just creating a ZIP file containing the executable and your project in the subfolder StartupProject. Please note that the name of the installation free executable of AIMMS can be changed freely.

See the two pictures below for an example I created with the Gate Assignment project that is in the AIMMS index of all examples.

Installation free deployment - Renamed executable

Installation free deployment - Renamed executable and StartupProject folder

In the picture above you can see that an installation free executable of AIMMS was renamed to Gate Assignment Solver.exe. When the user double clicks on this executable, this installation free version of AIMMS will start the first .prj file it can find the StartupProject folder. In the picture below, you can see that this is Gate Assignment.prj.

Installation free deployment - Contents StartupProject

Installation free deployment - Contents StartupProject

Note: Deploying this way does not automatically install a license. The first time a user starts the project, he/she will be asked to provide license information. If you will be deploying your application in combination with an AIMMS network license, you could skip this step by creating a configuration folder besides the StartupProject folder and use the –config-dir commandline option of AIMMS. For more information about this option, see the section “Calling AIMMS” in the AIMMS User’s guide.

This entry was posted in Advanced, Technical on by .

Display Multiple Identifiers in a 2D Chart

A 2D Chart not only makes it possible to display your AIMMS data in various two-dimensional chart types, such as a plot chart, a bar chart, a pie chart, etc, it also allows displaying multiple identifiers with different measurements and different chart types in the same chart, like the following.

In this charts, “Existing Resources” and “Capacity Deficit” are in MW and displayed as stacking bars; “Demand Growth” and “New Resources Growth” are in percentage and displayed as plot curves. In order to set this chart up, you only need to specify the Y-Axis and Y2-Axis properties in the 2D chart properties dialog as shown below.

The appearance of each identifier, for example, colors, width, labels, etc. can be modified to the desired look in the properties dialog.  For the details, you may check the attached 2D Chart example.

2D-Chart-Example
Title: 2D-Chart-Example (0 click)
Caption:
Filename: 2D-Chart-Example.aimmspack
Size: 40 kB

This entry was posted in Beginner on by .

Selecting variables and constraints for a Math Program

Selecting variables and constraints for Math Program

Selecting variables and constraints for Math Program

One of the features of AIMMS is that you can have multiple mathematical programs in one project, each having its own set of variables and constraints.

When you solve a mathematical program (or generate it via the GMP functions), AIMMS will use the values of the Constraints and Variables attributes of the mathematical program identifier to determine which symbolic variables and constraints should actually be considered in the model. In these Constraints and Variables attributes of the math program identifier, you must provide a subset of the predefined sets AllConstraints and AllVariables, respectively. Each of these sets must contain exactly those symbolic constraints/variables which should be considered when generating the model. If you do not provide any values (or leave the default as is), AIMMS by default will use AllConstraints and AllVariables. This means that all constraints and variables in your project will be considered.

You can create your own sets for constraints and variables to be considered by introducing two new set identifiers in AIMMS, e.g. ModelVariables and ModelConstraints. You then make ModelVariables a subset of the predefined set AllVariables and make ModelConstraints a subset of the predefined set AllConstraints. After that, in your math program identifier you should use these two new sets for the Variables and Constraints attributes. Finally, you can now set data for these two new sets, either by filling them in a procedure with data, or using the definition attribute of the set in to select which variables/constraints should be part of the subset.

Different approaches/methods can be used to fill these subsets of variables/constraints (automatically) with elements. I will show different examples for this in future blog articles.

Be careful with variables that have a definition. Please keep in mind that for each variable with a definition in your model, AIMMS will actually generate both the variable and additional equality constraint. For example, if you have the variable X that has Y + Z in its definition attribute, AIMMS will actually generate two things:

  • Variable X
  • Equality constraint X_definition defined as X = Y + Z

If you use the above mentioned approach of selecting certain variables and constraints for a mathematical program identifier in AIMMS, you must ensure that all the defined variables are also in the set of selected constraints. Otherwise, AIMMS would only consider the variable and not its corresponding equality constraint.

This entry was posted in Beginner, Technical on by .

Using block statement to temporary use other project settings

Temporary use other project settings for one or more statements

Temporary use other project settings for one or more statements

Sometimes it is useful to run one or more statements in AIMMS with a different value for one of the AIMMS project settings. As displayed in the figure on the right, statement 2 should be executed while one or more project settings temporary have a different value.

An example of this is the code in the article Inspecting SQL statements created by AIMMS, where you want to run certain statements with the database tracing options set to a specific value. One possibility is to manually store the option value before the statement(s), then modify the option and run the statement(s), after which you restore the original value.

This approach can also be done easier in AIMMS by using the block statement. The code in the other blog article can be rewritten to:

!Only trace SQL statements, and not the data itself
!And store the tracing information to the given file
block where 
        database_trace_level := 1,
        database_trace_file  := "TraceReadLocationTable.txt" ; 
 
    !Statements within this block are executed with the above project settings
 
    read from table LocationTable;
endblock ; 
 
!The two options will now have the same value they had before
!block statement
 
 
!Trace both SQL statements and data transferred 
!And store the tracing information to the given file
block where 
        database_trace_level := 2,
  	database_trace_file  := "TraceReadDepotTable.txt" ; 
 
    !Statements within this block are executed with the above project settings
 
    read from table DepotTable;
endblock ;

When using this block statement, AIMMS will take care of storing the value of the setting before the execution of the statements within the block and also restoring this original value after the execution of the statements in the block is finished.

This entry was posted in Beginner, Technical on by .

Check if given variable values satisfy all constraints

Verify if variable values satisfy all constraints

Verify if variable values satisfy all constraints

Sometimes you might want to check whether a given combination of value assignments for the variables in your model actually satisfy all the constraints. One possibility is to add an assignment constraint for each of your variables that fixes the variable to the given value and then solve the model again. If the solver returns with the status infeasible, you know that these variables values do not satisfy all constraints and otherwise the values of the variables are a feasible solution for your model.

Another approach to figure out whether the given values for the variables are a feasible solution that requires no modifications to your actual model, is to make use of the GMP function GMP::Solution::Check.

Suppose we have the following simple model:
\mathrm{min\ }x
s.t.
x + y \ge 5
x,y \ge 0

and we want to check whether the assignment x=1\ ,\ y=1 is actually a feasible solution. We must first add identifiers for the required variables (x,y,obj) and constraint to an AIMMS project. After that, you add a math program identifier that links these variables and constraints. Finally, we can then use the following code to actually check whether the assignment x=1\ ,\ y=1 is a feasible solution:

!We want to check if x=1, y=1 is a feasible solution for our MathProgram
 
!First we must generate the GMP for our MathProgram
generatedMP := GMP::Instance::Generate(
    MP   : MathProgram ) ; 
 
!Then we must assign the values we want to check to the variables
x := 1 ; 
y := 1 ; 
 
!Now retrieve the values from the variables in the model to
!solution number 1 of this generated math program.
GMP::Solution::RetrieveFromModel(
    GMP      : generatedMP , 
    solution : 1 ) ; 
 
 
!We can now use the GMP::Solution::Check to check solution
!number 1.
GMP::Solution::Check(
    GMP       : generatedMP , 	!The Math program we want to use
    solution  : 1 , 		!The solution number we want to check
    numInfeas : numberOfInfeasibilities , !store # of infeasibilities 
    sumInfeas : sumOfInfeasibilities ,    !store sum infeasibilities
    skipObj   : 1 ) ; 		!Objective can be skipped
 
 
 
!Now we can check the number of infeasibilities. If there are no 
!infeasibilities, it means the variables values satisfy all constraints
if numberOfInfeasibilities then 
  message := "Variable values do not satisfy all constraints:\n"  ; 
  message += "Number of infeasibilities = " + numberOfInfeasibilities + "\n" ; 
  message += "Sum of infeasibilities = " + sumOfInfeasibilities ; 
  dialogMessage( message ) ; 
else
  dialogMessage("Variable values are feasible for all constraints") ; 
endif ;

After running the above code, you will get the message that assignment x=1\ ,\ y=1 does not satisfy all the constraints.

You can download the above example code in a complete AIMMS project. Please note that this file can only be opened in AIMMS versions 3.11 and newer.

Check-Solution
Title: Check-Solution (0 click)
Caption:
Filename: Check-Solution.aimmspack
Size: 40 kB

This entry was posted in Advanced, Technical on by .

Operations Research Memes

To bring awareness of OR to the masses and get people to wonder what OR is, Tallys Yunes (O.R. by the beach) created some nice Operations Research related memes. One example of a meme he created is the following

One does not simply make decisions without OR

Boromir meme

Some other OR bloggers have created a couple of other memes already also. Tallys keeps a complete overview of what has been created in the “Operations Research Memes” article on his OR by the beach blog.

Update: Could not resist to create one myself also. Created it based on something I heard often from the students during my PhD years, namely that they were always talking about a solution that was even more optimal than the other solution.

Schrute meme

Schrute meme

This entry was posted in Fun on by .

Emptying sets

To remove all the elements from a set, you can use the empty statement in AIMMS. However, it is important to keep in mind that this empty statement might not have the desired effect in case the set you want to empty is a subset of the predefined set AllIdentifiers.

The behavior of the empty statement depends on the set that you provide as an argument:

  • The set is not a subset of AllIdentifiers. In this case the empty statement will remove all elements from the given set.
  • The set is a subset of AllIdentifiers. In this case the empty statement will empty all the identifiers that are in the given subset.

To demonstrate the difference, I will give a small example, for which we need the following two identifiers:

SET:
   identifier :  NormalSet
 
SET:
   identifier :  ActiveVariables
   subset of  :  AllVariables

As you can see, it holds that:

ActiveVariables \subseteq AllVariables \subseteq AllIdentifiers

because the predefined set AllVariables is defined in AIMMS to be a subset of AllVariablesConstraints, which in turn is subset of AllIdentifiers again. You can verify this by opening the attribute window of these predefined sets.

This means that the empty statement will have different behavior when used on NormalSet and on ActiveVariables:

!This will remove all elements from the set NormalSet 
empty NormalSet ; 
 
!This will clear the values of all variables in the subset ActiveVariables
!After the empty statement, the set itself will still contain elements!
empty ActiveVariables ;
 
!This will actually remove all elements from the set ActiveVariables 
ActiveVariables := {} ;
This entry was posted in Beginner, Technical on by .

Inspecting SQL statements created by AIMMS

When you are reading/writing data from/to a database with AIMMS via database table identifiers, internally AIMMS will communicate with the database via SQL statements.

If you have a situation where you expect data to be present in AIMMS after a database read, but it is not, you have the option to instruct AIMMS to output the actual SQL statements that are executed to communicate with the database.

By default, AIMMS will not log this information. You can modify this behavior by changing the two project settings

  • Database trace file: indicates to which file the information should be logged,
  • Database trace level: indicates how much information should be logged:
    • 0 – No tracing
    • 1 – Only trace the SQL statements without the data
    • 2 – Trace the SQL statements including the data

You can set these project options via the Project Options in the settings menu, or within the AIMMS Code. For example, the code below will switch on statement-only tracing for the first read statement and statement-and-data tracing for the second read statement. Finally, the tracing is switched off again for subsequent database communication.

!Only trace SQL statements, and not the data itself
OptionSetValue("Database trace level", 1) ;
!And store the tracing information to this file
option database_trace_file := "TraceReadLocationTable.txt";
 
read from table LocationTable;
 
!Trace both SQL statements and data transferred 
OptionSetValue("Database trace level", 2) ;
!And store the tracing information to this file
option database_trace_file := "TraceReadDepotTable.txt";
 
read from table DepotTable;
 
!Switch off the tracing again for subsequent communication
OptionSetValue("Database trace level", 0) ;

The above code will create a separate trace file for both read statements. The contents of the TraceReadLocationTable.txt file will be the following:

Starting transaction on datasource "AIMMS Transport Example Database.udl"
Creating SELECT command for AIMMS READ statement: SELECT `Location`, `XCoord`, `YCoord` FROM `Locations`
Start executing READ statement
Reading data with SELECT statement
End executing READ statement (75 row(s) read)
Committing transaction on datasource "AIMMS Transport Example Database.udl"

While the contents of the TraceReadDepotTable.txt file will be the following:

Starting transaction on datasource "AIMMS Transport Example Database.udl"
Creating SELECT command for AIMMS READ statement: SELECT `Depot`, `Supply` FROM `Depots`
Start executing READ statement
Reading data with SELECT statement
	Column 1; Type: WString; Value: "Eindhoven"
	Column 2; Type: Double; Value: 14500.000000
	Column 1; Type: WString; Value: "Haarlem"
	Column 2; Type: Double; Value: 10800.000000
	Column 1; Type: WString; Value: "Heerenveen"
	Column 2; Type: Double; Value: 14300.000000
	Column 1; Type: WString; Value: "Middelburg"
	Column 2; Type: Double; Value: 12400.000000
	Column 1; Type: WString; Value: "Zutphen"
	Column 2; Type: Double; Value: 13000.000000
End executing READ statement (5 row(s) read)
Committing transaction on datasource "AIMMS Transport Example Database.udl"

When using these tracing options, please keep in mind that especially tracing with all data (i.e. database trace level = 2) can result in very large trace files.

This entry was posted in Advanced, Technical on by .

Various (integer) linear modeling tricks

Modeling problems with an (integer) linear program sometimes requires some experience to recognize certain structures in the problem description that can be formulated in a linear way.

On the website of the Naval Postgraduate School, you can find the document Formulating Integer Linear Programs: A Rogues’ Gallery that tries to demystify the art of formulating linear and integer linear programs. They do this by introducing formulettes, which consist of a verbal description and the constraints and variables that model this verbal description.

The first simple example of a formulette they provide is the following:

For each unit of X_1, there must be at least 5 units of X_2

which can be modeled with

5X_1 le X_2.

The document contains a lot more of such formulettes of varying complexity.

Furthermore, in our book Optimization Modeling you can also find various modeling tricks in the chapters “Linear Programming Tricks” and “Integer Programming Tricks”. The Optimization Modeling book can either be found online via the link above, or you can find it under the Help menu after you started AIMMS.

This entry was posted in Beginner, Technical on by .

Determine consecutive range in Excel

Some of the Excel functions in AIMMS require you to provide one or more ranges as an argument. Sometimes, the developer will not know beforehand how many rows / columns the end-user wants to read in. In this case, there are two options to ensure all the required data is read in:

  • Named Ranges: the developer requires the user to add (and maintain) named ranges in the Excel sheet itself. This way, the AIMMS developer can always refer to this named range, while the end-user will have to ensure that the named range is actually correct.
  • Programmatically determine first empty cell: the developer will take a start cell and a direction and determine the first cell in the given direction that does not contain a value.

This second approach has the advantage that the modeller/end-user will only have to work a start-cell and a direction as the end-cell of the consecutive range will be determined with AIMMS code. The code that can be used for this can be found in the following .aim file, which you can import into a section by following the instructions from the article Exporting a section and importing it in another AIMMS project.

DetermineConsecutiveRange
Title: DetermineConsecutiveRange (0 click)
Caption:
Filename: DetermineConsecutiveRange.aim
Size: 4 kB

 After you imported the above section, you can use it in your AIMMS code. The procedure DetermineConsecutiveRange has three input arguments and one output argument:

  • whichWorkbook (input): string parameter containing workbookname
  • startCell (input): string parameter containing the start cell
  • cellDirection (input): parameter indicating direction (1=left, 2=right, 3=up, 4=down)
  • endCell (output): after procedure is finished, this parameter will contain the last cell in the given direction that still contains a value

If you have two string parameters rangeStartCell and rangeEndCell, you can use the procedure as follows:

!First set the active sheet for workbook denoted by the string parameter
!WorkbookName to sheet "Transport Model"
ExcelSetActiveSheet( WorkbookName, "Transport Model" );

!Set the start cell for the range
rangeStartCell := "A4" ; 

!Now we want to determine the range of cells that contain 
!values going from A4 down
DetermineConsecutiveRange(
	whichWorkbook :  WorkbookName, 
	startCell     :  rangeStartCell , 
	cellDirection :  4,  !4 indicates we want to look down-wards
	endCell       :  rangeEndCell ) ; 

!Now the total range that can be given as an argument to any of
!the Excel functions is given by rangeStartCell:rangeEndCell

DialogMessage("Consecutive range = " + rangeStartCell + ":" + rangeEndCell) ; 
This entry was posted in Beginner, Technical on by .
  • Customer Reviews

    Read more AIMMS reviews
  • Review AIMMS on G2 Crowd
  • Recent Posts

  • Categories