How to create mappings for matrix-oriented data via name-binds-to
Sometimes your data source consists of both column- and row-oriented data, showing data matrix-style. For these setups you can still use a mapping file, using certain elements in your tags to guide the data to the correct identifier(s). In this how-to, we’ll use an example to show you how to write the corresponding mapping files.
Running example
When creating a diet, care is taken to adhere to limits on selected ingredients. The actual selection of ingredients that is important to a person depends on the person. For instance, some people need restrictions on salt and some people need restrictions on refined sugar. And so on. Also, the availability of products, and their fractions of these ingredients, varies over time and location.
Thus the core information used to create a diet depends on a matrix that looks like this:
Whereby both the collection of
foods, and
nutrients
vary.
The purpose of this article is to illustrate the use of Data Exchange Library, and in particular the mapping attribute name-bind-to, to flexibly and compactly specify exchanging data between data source and AIMMS. In this example, the data source is an EXCEL workbook.
The running example is based on the Diet Problem example from AIMMS The modeling guide.
A selection of the declarations:
Nutriets, index: \(n\). In model:
i_n
ins_nutrients
Food types, index: \(f\). In model:
i_f
ins_foodTypes
Fractions: Nutrient value per unit of food, \(fr_{f,n}\). In model:
p_nutrientValuePerUnit(i_f,i_n)
The corresponding AIMMS 4.84 project can be downloaded here
Mapping file version 1
1<?xml version="1.0"?>
2<AimmsExcelMapping>
3 <ExcelSheetMapping name="foodnutrient">
4 <RowMapping>
5 <ColumnMapping name="food" binds-to="i_f" />
6 <ColumnMapping name-binds-to="i_n" name-regex=".*" maps-to="p_nutrientValuePerUnit(i_f,i_n)" />
7 </RowMapping>
8 </ExcelSheetMapping>
9 <ExcelSheetMapping name="food">
10 <RowMapping>
11 <ColumnMapping name="food" binds-to="i_f" />
12 <ColumnMapping name="maxQnt" maps-to="p_maximumNumberOfServings(i_f)" />
13 <ColumnMapping name="Price" maps-to="p_pricePerUnit(i_f)" />
14 <ColumnMapping name="Weight" maps-to="p_weightOfFoodType(i_f)" />
15 </RowMapping>
16 </ExcelSheetMapping>
17 <ExcelSheetMapping name="nutrient">
18 <RowMapping>
19 <ColumnMapping name="nutrient" binds-to="i_n" />
20 <ColumnMapping name="atMost" maps-to="p_maximumAllowanceOfNutrient(i_n)" />
21 <ColumnMapping name="atLeast" maps-to="p_minimumRequirementOfNutrient(i_n)" />
22 </RowMapping>
23 </ExcelSheetMapping>
24</AimmsExcelMapping>
Remarks:
Lines 5,6: The sheet
foodnutrient
is used for exchanging data with the parameterp_nutrientValuePerUnit(i_f,i_n)
as follows:Rows are mapped to the
s_foodTypes
set. The<ColumnMapping/>
element uses the following attributes:name="food"
: The row names are taken from the column with namefood
binds-to="i_f"
: in the AIMMS model, these row names are mapped to element names in the sets_foodTypes
as this set is the range of the indexi_f
.
This mapping element is also used for CSV and Parquet files.
Columns are mapped to the
s_nutrients
set. The<ColumnMapping/>
element uses the following attributes for this purpose:name-binds-to="i_n"
This indicates that the names of columns, in row 1, are input for the indexi_n
.name-regex=".*"
This regular expression rule on the column names indicates that the column names can be used as is for the sets_nutrients
. More about name-regex as part ofname-binds-to
.maps-to="p_nutrientValuePerUnit(i_f,i_n)"
As the indicesi_f
andi_n
are now bound, the EXCEL content can be assigned to this parameter.
The sheets
food
andnutrient
are used for exchanging data with the other parameters, indexed overi_f
andi_n
respectively.
In this section, two sheets were used to present the data regarding the foods. One for the nutrients, and one for the other aspects of each food. It is possible to combine these two sheets into one; provided the data for the nutrients is clearly identified.
Mapping file version 2
By combining the information from the sheets foodnutrient
and food
, we get a sheet that looks as follows:
Note that the column names for the nutrients are now prefixed with nut-
.
We use this in the mapping as specified below.
1<?xml version="1.0"?>
2<AimmsExcelMapping>
3 <ExcelSheetMapping name="foodnutrient">
4 <RowMapping>
5 <ColumnMapping name="food" binds-to="i_f" />
6 <ColumnMapping name="maxQnt" maps-to="p_maximumNumberOfServings(i_f)" />
7 <ColumnMapping name="Price" maps-to="p_pricePerUnit(i_f)" />
8 <ColumnMapping name="Weight" maps-to="p_weightOfFoodType(i_f)" />
9 <ColumnMapping name-binds-to="i_n"
10 name-regex=".*"
11 name-regex-prefix="nut-"
12 maps-to="p_nutrientValuePerUnit(i_f,i_n)" />
13 </RowMapping>
14 </ExcelSheetMapping>
15 <ExcelSheetMapping name="nutrient">
16 <RowMapping>
17 <ColumnMapping name="nutrient" binds-to="i_n" />
18 <ColumnMapping name="atMost" maps-to="p_maximumAllowanceOfNutrient(i_n)" />
19 <ColumnMapping name="atLeast" maps-to="p_minimumRequirementOfNutrient(i_n)" />
20 </RowMapping>
21 </ExcelSheetMapping>
22</AimmsExcelMapping>
Remarks:
All that is indexed over
food
is now moved in theExcelSheetMapping
on lines 3-14.Line 11: New is the prefix “nut-”. This prefix is used in two ways:
To recognize a column that contains nutrient information.
To remove the prefix from the column name before adding that name to the set
s_nutrients
.