Introduction to RASON
About RASON Models and the RASON Server
Rason Subscriptions
Rason Web IDE
Creating and Running a Decision Flow
Defining Your Optimization Model
Defining Your Simulation Model
Performing Sensitivity Analysis
Defining Your Stochastic Optimization Model
Defining Your Data Science Model
Defining Custom Types
Defining Custom Functions
Defining Your Decision Table
Defining Contexts
Using the REST API
REST API Quick Call Endpoints
REST API Endpoints
Decision Flow REST API Endpoints
OData Endpoints
OData Service for Decision Flows
Creating Your Own Application
Using Arrays, For, Loops and Tables
Organization Accounts

Using Tables

Recall from the earlier Array Formulas section that arrays in the RASON Modeling language are limited to 2-dimensions. If you require an array containing more than 2-dimensions, a table may be created. There are many advantages to using tables:

  • Tables may hold more than 2 dimensions
  • A table result may be used in an indexed array formula
  • A table can be sparse while an array is dense.
  • The evaluation of a table is less expensive (time consuming) than the evaluation of an array with more than 2 dimensions.

The following matrix of data displays the number of each part used in the manufacturing of three products: TVs, stereos and speakers.

Parts TVs Stereos Speakers
Chassis 1 1 0
LCD Screens 1 0 0
Speaker Cones 2 2 1
Power Supply 1 1 0
Electronics 2 1 1

In the example code below, the matrix above has been specified "in line" (within the RASON model) as the parts table. This table contains 15 elements, the same as the matrix above, and is indexed using two dimensions: part and prod. (To open this full example, and any example referenced in this guide, click the down array under RASON examples on the Try It page of www.RASON.com or browse to C:\Program Files\Frontline Systems\Analytic Solver Platform\Solver SDK Platform\Examples\RASON if using the RASON IDE.)

 data: {
   parts: { indexCols: ['part', 'prod'],
   value: [
['chas', 'tv', 1], ['chas', 'stereo', 1], ['chas', 'speaker', 0],
['lcds', 'tv', 1], ['lcds', 'stereo', 0], ['lcds', 'speaker', 0],
['cone', 'tv', 2], ['cone', 'stereo', 2], ['cone', 'speaker', 1],
['psup', 'tv', 1], ['psup', 'stereo', 1], ['psup', 'speaker', 0],
['elec', 'tv', 2], ['elec', 'stereo', 1], ['elec', 'speaker', 1]] 
   }
},
variables : {
   x: {dimensions: ['prod'], value: 0, lower: 0, finalValue: [] },
},
constraints : {
	  c1: {formula: "sumproduct(parts['chas',], x)", upper: 450 },
	  c2: {formula: "sumproduct(parts['tube',], x)", upper: 250 },
	  c3: {formula: "sumproduct(parts['cone',], x)", upper: 800 },
	  c4: {formula: "sumproduct(parts['psup',], x)", upper: 450 },
	  c5: {formula: "sumproduct(parts['elec',], x)", upper: 600 }},
 objective : {
total: {formula: "sumproduct(x, profits)", type: "maximize", finalValue: [] }
}

Notice that even though the parts table is listed horizontally in the RASON model, the table elements are stored in a vertical array.

In the variables section, the x array, dimensioned using the index column prod, is an array of size 3 containing our decision values x[1], x[2] and x[3]. These are the number of each product to produce.

In the constraints section, five constraints are formulated by "slicing" the table to obtain the correct part data. For example, in the first constraint, c1, parts['chas', ] slices the table across the part chas which results in the elements: 1, 1, 0. The second constraint, c2, slices the table across tube obtaining the elements 1, 0, 0. Constraints c3, c4 and c5 are calculated in the same fashion.

Since tables are sparse, as opposed to arrays which are dense, we can eliminate the table elements that are not non-zero. This leaves the following table that is still indexed with two dimensions, part and prod, but now only contains 11 elements. (See the example model RGProductMixTab1.json to view the complete model.)

Note: In the current release of the RASON Modeling Language, the overall internal structure of the table is dense, the missing records are considered 0's.

parts: {indexCols: ['part', 'prod'],
		value: 
       [['chas', 'tv', 1],
		['chas','stereo', 1],			
		['tube', 'tv', 1],
		['cone', 'tv', 2],
		['cone', 'stereo', 2],
		['chas', 'stereo', 1],
		['cone', 'speaker', 1],
		['psup', 'tv', 1],
		['psup', 'stereo', 1],
		['elec', 'tv', 2],
		['elec', 'stereo', 1],
		['elec', 'speaker', 1]] 
},

Note that the order in which the table elements are entered is irrelevant since we are supplying both dimensions for each value. We could have also entered the table as:

parts: {indexCols: ['part', 'prod'],
  	value: 
       [['chas', 'tv', 1],
		['tube', 'tv', 1],			
		['cone', 'tv', 2],
		['psup', 'tv', 1],
		['elec', 'tv', 2],
		['chas', 'stereo', 1],
		['cone', 'stereo', 2],
		['psup', 'stereo', 1],
		['elec', 'stereo', 1],
		['cone', 'speaker', 1],
		['elec', 'speaker', 1]] 
},

The ProductMixTab2.json example model illustrates how to use an index set to dimension a table. RASON uses index sets exclusively to dimension tables and arrays. Typical mathematical programming models include multiple tables and arrays indexed over various index sets. An index set should be created at the beginning of the model to establish a basis of order for each dimension appearing in a table or array. Otherwise, the user will be required to keep track of and maintain the correct order of elements in all arrays and tables present in the model. An index set is always a 1-dimensional array and must be defined within the indexSets section of the RASON model.

The example code below creates two ordered sets, part and prod. The part set contains five items (in order as entered): chas, tube, cone, psup and elec while the prod set contains 3 items: tv, stereo and speakers. For more information on index sets, see the Index Sets section within the RASON Reference Guide.

indexSets: {
        part: {
            value: ['chas', 'tube', 'cone', 'psup', 'elec']
        },
        prod: {
            value: ['tv', 'stereo', 'speaker']
        }

    },
data: {
        parts: {
            indexCols: ['part', 'prod'],
            value: [
			
                ['chas', 'tv', 1],
                ['chas', 'stereo', 1],
                ['tube', 'tv', 1],
                ['cone', 'tv', 2],
                ['cone', 'stereo', 2],
                ['cone', 'speaker', 1],
                ['psup', 'tv', 1],
                ['psup', 'stereo', 1],
                ['elec', 'tv', 2],
                ['elec', 'stereo', 1],
                ['elec', 'speaker', 1]
            ]
        },
        profits: {
            dimensions: ['prod'],
            value: [75, 50, 35]
        },
inventory: {dimensions: ['part'], value: [450, 250, 800, 450, 600], binding: "get", finalValue: [] }
}
formulas : {
	piv_parts: {formula: "PIVOT(parts, { 'prod' }, { 'part' })" }
    },
constraints : {
    c: {dimensions: ['part'], formula: "MMULT(piv_parts, x) - inventory", upper: 0 }
    },

In the data section, an inline table object, parts, is created containing two index columns (parts and prods) and a value column. Since the index set prod exists, we can dimension the profits array according to this set in order to assign the correct profit values to the appropriate products. Likewise, we can dimension the inventory array according to the part set in order to assign the correct inventory level to each part.

Notice the use of the PIVOT function in the piv_parts formula. Recall that a table is stored as a vertical array. The PIVOT function returns a 2-dimensional table (or a 1- dimensional table) of values with rows and columns assigned by the index columns in the table passed as the first argument. (The first argument passes the data.) The second argument is the index column(s) to be assigned as column(s) in the PIVOT table. (These are the dimensions that will make up the columns of the table.) The third argument is the index column(s) to be assigned as row(s) in the PIVOT table. (These are the dimensions that will make up the rows of the table.) In this example, our table parts contains two index columns, parts and prods. The PIVOT function creates a 2-dimensional array of values by assigning the prod dimension (TV, Stereos and Speakers) as columns and the part dimension(chas, cone, elec, psup and tube) as rows. The result is a 5 x 3 matrix.

Since piv_parts is now a 2-dimensional table, we can perform matrix multiplication using the MMULT (inherited from Excel) function to multiply this table by the variable array, x (which is also a vertical array). The result of this operation is a vertical array of size 5 which must be less than the inventory array (enforced by the upper property of 0).

If the sortindexCols (or sort) property is used, all indexCols will be sorted alphabetically. (Note: The properties sort and sortIndexCols perform the same function.) Otherwise, the table will be sorted as entered. In the example below, the order for the prod indexCol will be: speaker, stereo, tv. While the order for the part indexCol will be: chas, cone, elec, psup, tube.

data : {
  parts: {indexCols: ['part', 'prod'], sortIndexCols: true,
     value: [
	['chas', 'tv', 1], ['chas', 'stereo', 1], ['chas', 'speaker', 0],
	['tube', 'tv', 1], ['tube', 'stereo', 0], ['tube', 'speaker', 0],
	['cone', 'tv', 2], ['cone', 'stereo', 2], ['cone', 'speaker', 1],
	['psup', 'tv', 1], ['psup', 'stereo', 1], ['psup', 'speaker', 0],
	['elec', 'tv', 2], ['elec', 'stereo', 1], ['elec', 'speaker', 1]] 
  },

The table below gives a recap on how table elements may be referenced. See the list below for syntax in obtaining coefficients for dimensions and dimension slices in a table created using an index set.

Formula Syntax Action
parts['cone', ] Retrieves coefficients for all products containing the part, cone. The result is a vertical array.
parts[ ,'tv'] Retrieves coefficients for all parts used to build a TV. The result is a vertical array.
['cone', 'stereo'] Retrieves coefficient for part = 'cone' and prod='stereo'.

Back to Using Statements