Hierarchical composite objects

Can a component in a composite object be a composite object itself? Is it possible to hierarchically construct composite objects and use the AIMMS language which is an algebraic language?

The component based approach supports this by recursively enumerating all components in all declarations over the sets of composite objects. This article will not present a worked example as the details drag on and on.

The reference element based approach permits this. This article is a companion article to Modeling composite objects and refines the running example introduced there.

The AIMMS 4.82 project download

The refinement of the running example

The running example refers to 6 locations that are also nodes: ParisP, ParisD, Stockholm, Madrid, Berlin, and Rome. The first two nodes are located in Paris, one being a Production and the other a Distribution node.

Each node actually has two components: the location and the facility type. In the companion articles, the arcs were modeled as two components: a from and a to node. So why don’t we structure the arcs and nodes as follows:

../../_images/composite-objects.png

Declaring and using the node type

The node type is declared in AIMMS as follows:

 1Set s_locations {
 2    Index: i_loc;
 3}
 4Set s_nodeTypes {
 5    Index: i_nt;
 6    Definition: data { Production, Distribution };
 7}
 8StringParameter sp_shortTypeName {
 9    IndexDomain: i_nt;
10    Definition: data { Production : "PR",  Distribution : "DC" };
11}
12Set s_nodeIds {
13    Index: i_node, i_nodeFrom, i_nodeTo;
14}
15ElementParameter ep_nodeLocation {
16    IndexDomain: i_node;
17    Range: s_locations;
18}
19ElementParameter ep_nodeType {
20    IndexDomain: i_node;
21    Range: s_nodeTypes;
22}

With these declarations, we can define the set of s_productionNodes as follows:

1Set s_productionNodes {
2    SubsetOf: s_nodeIds;
3    Definition: {
4        { i_node | ep_nodeType(i_node) = 'Production' }
5    }
6}

Declaring and using the arc type

The arc type is declared as before, namely as follows:

 1Set s_arcIds {
 2    Index: i_arc;
 3    webui::ElementTextIdentifier: sp_arcName( i_arc );
 4}
 5ElementParameter ep_arcNodeFrom {
 6    IndexDomain: i_arc;
 7    Range: s_nodeIds;
 8}
 9ElementParameter ep_arcNodeTo {
10    IndexDomain: i_arc;
11    Range: s_nodeIds;
12}

With the declaration of both nodes and arcs, we can select the arcs coming from a production location as follows:

1Set s_arcsComingFromProduction {
2    SubsetOf: s_arcIds;
3    Index: i_pa;
4    Definition: {
5        { i_arc | ep_nodeType( ep_arcNodeFrom(i_arc) ) = 'Production' }
6    }
7}

Text input data

Part of the input for this model can be presented as AIMMS Composite tables as follows:

 1Composite table:
 2    i_node    ep_nodeLocation(i_node)  ep_nodeType(i_node)  p_initialStock(i_node)  p_productionCap(i_node)
 3!   ------    -----------------------  -------------------  ----------------------  -----------------------
 4    node-1    Paris                    Production                               10                        7
 5    node-2    Paris                    Distribution
 6    node-3    Stockholm                Production                                9                        7
 7    node-4    Madrid                   Distribution
 8    node-5    Berlin                   Distribution
 9    node-6    Rome                     Distribution
10    ;
11
12Composite table:
13    i_arc     ep_arcNodeFrom(i_arc)  ep_arcNodeTo(i_arc)  p_cost(i_arc)
14!   ------    ---------------------  -------------------  -------------
15    arc001    node-1                 node-2
16    arc002    node-1                 node-3                           3
17    arc003    node-1                 node-4                           4
18    arc004    node-1                 node-5                           5
19...
20;

Reporting the node and arc names

Clearly, as we have to look up the interpretation of a node name, it is not immediately clear what an arc is. This can be improved in the reporting, as the screenshot of a WebUI widget of the solution shows below:

../../_images/hierarchy-list.png

This is achieved using the following report naming of nodes and arcs (i.e. the element text annotation):

In the node name definition, we assume that the decision maker / end user knows which facility type is used for each location, except when there are multiple facilities in one location.

 1StringParameter sp_nodeName {
 2    IndexDomain: i_node;
 3    Definition: {
 4        if p_noNodesPerLocation(ep_nodeLocation( i_node)) = 1 then
 5            formatString("%e", ep_nodeLocation( i_node) )
 6        else
 7            formatString("%e (%s)", ep_nodeLocation( i_node),
 8                sp_shortTypeName( ep_nodeType( i_node ) ) )
 9        endif
10    }
11}

Once we have a clarifying node name, we can use that node name in the arc name as follows:

1StringParameter sp_arcName {
2    IndexDomain: i_arc;
3    Definition: {
4        formatString( "%s %s %s",
5            sp_nodeName( ep_arcNodeFrom( i_arc ) ),
6            character( 10230 ), ! Long right arrow (unicode char).
7            sp_nodeName( ep_arcNodeTo(   i_arc ) ) )
8    }
9}

Comparing deprecated compound sets and the reference element based approach

An advantage of the reference element based approach: The reference element based approach allows for hierarchical construction of objects as illustrated in this article. This was not offered in the now deprecated compound sets.

A functionality of the deprecated compound sets: The deprecated compound sets allowed to declare per composite object but also to use the component based approach in expressions.

 1Set s_nodes {
 2    Index: i_node, i_nodeFrom, i_nodeTo;
 3}
 4Set s_arcs {
 5    SubsetOf: (s_nodes, s_nodes);
 6    Tags: (afrom, ato);
 7    Index: i_arc;
 8}
 9Variable v_flow {
10    IndexDomain: i_arc;
11    Range: free;
12}
13Parameter p_totFlowCompBased {
14    Definition: sum( (i_nodeFrom, i_nodeTo), v_flow(i_nodeFrom, i_nodeTo) );
15}
16Parameter p_totFlowRefBased {
17    Definition: sum( i_arc, v_flow(i_arc) );
18}
19Parameter p_totInFlowCompBased {
20    IndexDomain: i_node;
21    Definition: sum( i_nodeFrom, v_flow(i_nodeFrom, i_node) );
22}
23Parameter p_totInFlowRefBased {
24    IndexDomain: i_node;
25    Definition: sum( i_arc | i_arc.ato = i_node, v_flow(i_arc) );
26}

On lines 14 and 21 the component based approach is used in using v_flow. On lines 17 and 25 the reference element based approach is used in using v_flow.

Whether or not mixing the component and reference element based approach is an advantage is debatable. In Modeling composite objects it is shown that using the reference element based approach is clearer. Even when selecting arcs using element parameters or tags to refer to the components of a composite object.