4 #ifndef TREE_STRATEGY_3D_TORUS_MIN_HOPS
5 #define TREE_STRATEGY_3D_TORUS_MIN_HOPS
8 /** A concrete tree builder for use on machines with a 3D Torus topology. Naturally, can also work with
9 * 3D meshes (portions of the torus).
11 * Reduces hop-bytes by trying to reduce the total number of hops across the tree. Is implicitly
12 * node-aware as on-node PEs will have a distance of zero and will end up as direct children in the
13 * spanning tree. Does not pay any attention to reducing the number of bytes on the network by
14 * minimizing inter-node traffic. For that, refer to SpanningTreeStrategy_3dTorus_minBytesHops.
16 * Specialized and implemented only for data type in input container = vtxType / SpanningTreeVertex.
17 * @note: If its a container of SpanningTreeVertices, the next gen info is stored in the parent
18 * element and a copy of the parent is also returned.
20 template <typename Iterator
,typename ValueType
= typename
std::iterator_traits
<Iterator
>::value_type
>
21 class SpanningTreeStrategy_3dTorus_minHops
: public SpanningTreeStrategy
<Iterator
>
24 virtual SpanningTreeVertex
* buildNextGen(const Iterator firstVtx
, const Iterator beyondLastVtx
, const int maxBranches
=2) = 0;
29 /** Partial specialization for scenario for a container of SpanningTreeVertices
31 template <typename Iterator
>
32 class SpanningTreeStrategy_3dTorus_minHops
<Iterator
,SpanningTreeVertex
>: public SpanningTreeStrategy
<Iterator
>
35 virtual SpanningTreeVertex
* buildNextGen(const Iterator firstVtx
, const Iterator beyondLastVtx
, const int maxBranches
=2);
40 /** Partial specialization for scenario when a container of vtxTypes is input.
42 * Simply builds a container of SpanningTreeVertices from the input data and delegates the actual
43 * tree building to another specialization.
45 template <typename Iterator
>
46 class SpanningTreeStrategy_3dTorus_minHops
<Iterator
,vtxType
>: public SpanningTreeStrategy
<Iterator
>
49 virtual SpanningTreeVertex
* buildNextGen(const Iterator firstVtx
, const Iterator beyondLastVtx
, const int maxBranches
=2)
51 /// Create a container of SpanningTreeVertices from the input container and fill it with vertex IDs
52 std::vector
<SpanningTreeVertex
> tree
;
53 for (Iterator itr
= firstVtx
; itr
!= beyondLastVtx
; itr
++)
54 tree
.push_back( SpanningTreeVertex(*itr
) );
55 /// Instantiate the real builder and let it build the next generation
56 SpanningTreeStrategy_3dTorus_minHops
< std::vector
<SpanningTreeVertex
>::iterator
> theRealBuilder
;
57 SpanningTreeVertex
*result
= theRealBuilder
.buildNextGen(tree
.begin(),tree
.end(),maxBranches
);
58 /// Copy the reordered vertex indices back into the user's data structure
60 for (Iterator itr
= firstVtx
; itr
!= beyondLastVtx
; itr
++)
65 /// Return information about the parent vertex (which contains child indices etc)
74 * Utility class to partition the bounding box of a spanning (sub)tree on a 3D mesh machine and
75 * divide that into the necessary number of branches
77 template <typename Iterator
>
78 class TreeBoundingBoxOn3dTorus
81 /// Partition the range along the longest dimension into numPartitions parts
82 void partition(const Iterator parent
, const Iterator start
, const Iterator end
, const int numPartitions
);
85 /// Bisect the range along the longest dimension
86 void bisect(const Iterator parent
, const Iterator start
, const Iterator end
, const int numPartitions
);
87 /// Trisect the range along the longest dimension
88 void trisect(const Iterator parent
, const Iterator start
, const Iterator end
, const int numPartitions
);
89 /// Returns the dimension along which the bounding box of a range of vertices has the longest side
90 int findMaxSpreadDimension(const Iterator start
, const Iterator end
);
91 /// Configure a lessThan functor to compare vertices
95 lessThan(const int _dim
): dim(_dim
) {}
96 inline bool operator() (const SpanningTreeVertex
&a
, const SpanningTreeVertex
&b
)
98 return (a
.X
[dim
] < b
.X
[dim
]);
104 } // end namespace impl
106 } // end namespace topo
109 #include "TopoManager.h"
113 template <typename Iterator
>
114 SpanningTreeVertex
* SpanningTreeStrategy_3dTorus_minHops
<Iterator
,SpanningTreeVertex
>::buildNextGen(const Iterator firstVtx
, const Iterator beyondLastVtx
, const int maxBranches
)
116 /// If the parent vertex already has a(n older) list of children, clear it
117 (*firstVtx
).childIndex
.clear();
118 (*firstVtx
).childIndex
.reserve(maxBranches
);
120 /// Get a handle on a TopoManager. @note: Avoid this per-call instantiation cost by using an instance manager? Ideally, TopoManager should be a singleton.
121 TopoManager aTopoMgr
;
122 /// Find the machine coordinates of each vertex
123 for (Iterator itr
= firstVtx
; itr
!= beyondLastVtx
; itr
++)
126 (*itr
).X
.assign(3,0);
127 int coreNum
; ///< dummy var. Get and discard the core number
128 aTopoMgr
.rankToCoordinates( (*itr
).id
, (*itr
).X
[0], (*itr
).X
[1], (*itr
).X
[2], coreNum
);
130 ///@todo: If the machine coordinates are already stored in the vertices, do we want to find them again?
132 /// Partition the vertex bounding box into maxBranches portions
133 Iterator firstDescendant
= firstVtx
;
134 impl::TreeBoundingBoxOn3dTorus
<Iterator
> treePart
;
135 treePart
.partition(firstVtx
,++firstDescendant
,beyondLastVtx
,maxBranches
);
137 /// Identify the closest member in each subtree and put it at the corresponding childIndex location
138 for (int i
=0, numChildren
=(*firstVtx
).childIndex
.size(); i
<numChildren
; i
++)
140 Iterator rangeStart
= firstVtx
;
141 std::advance(rangeStart
,(*firstVtx
).childIndex
[i
]);
142 Iterator rangeEnd
= firstVtx
;
143 if (i
+1 == numChildren
)
144 rangeEnd
= beyondLastVtx
;
146 std::advance(rangeEnd
, (*firstVtx
).childIndex
[i
+1] );
147 Iterator closestItr
= pickClosest(*firstVtx
,rangeStart
,rangeEnd
);
148 std::iter_swap(rangeStart
,closestItr
);
150 /// Return a copy of the parent in keeping with the generic interface
151 return (new SpanningTreeVertex(*firstVtx
) );
158 template <typename Iterator
>
159 inline void TreeBoundingBoxOn3dTorus
<Iterator
>::partition(const Iterator parent
, const Iterator start
, const Iterator end
, const int numPartitions
)
161 /// Find the number of vertices in the range
162 int numVertices
= std::distance(start
,end
);
163 /// If further partitioning is needed and there are vertices left to partition
164 if ( (numPartitions
> 1) && (numVertices
> 1) )
166 if (numPartitions
% 3 == 0)
167 trisect(parent
,start
,end
,numPartitions
);
169 bisect (parent
,start
,end
,numPartitions
);
171 /// else, just register the remaining vertex(ices) as a sub-tree
172 else if ( (numPartitions
>= 1) && (numVertices
>= 1) )
174 int indx
= std::distance(parent
,start
);
175 (*parent
).childIndex
.push_back(indx
);
177 /// else if there are no vertices left, do nothing
178 else if (numVertices
== 0)
181 /// else, if there are vertices remaining but no partitions to put them in
182 else if ( (numVertices
>= 0) && (numPartitions
== 0) )
183 CkAbort("\nThere are vertices left but no remaining partitions to put them in.");
184 /// fall through case. Should never get here unless something is wrong
186 CkAbort("\nPartitioning fell through to the default case (which it never should). Check the logic in this routine.");
191 template <typename Iterator
>
192 void TreeBoundingBoxOn3dTorus
<Iterator
>::bisect(const Iterator parent
, const Iterator start
, const Iterator end
, const int numPartitions
)
194 /// Find the number of vertices in the range
195 int numVertices
= std::distance(start
,end
);
196 /// Find the dimension along which to bisect the bounding box
197 int maxSpreadDim
= findMaxSpreadDimension(start
,end
);
198 /// Pin the location of the median element
199 Iterator median
= start
;
200 std::advance(median
,numVertices
/2);
201 /// Bisect the vertex list at the median element
202 std::nth_element( start
, median
, end
, lessThan(maxSpreadDim
) );
203 /// Partition the two pieces as necessary
204 int numLeft
= numPartitions
/2;
205 partition(parent
, start
, median
, numLeft
);
206 partition(parent
, median
, end
, numPartitions
- numLeft
);
211 template <typename Iterator
>
212 void TreeBoundingBoxOn3dTorus
<Iterator
>::trisect(const Iterator parent
, const Iterator start
, const Iterator end
, const int numPartitions
)
214 /// If the number of partitions left really can be trisected, then do it
215 if (numPartitions
% 3 == 0)
217 /// Find the number of vertices in the range
218 int numVertices
= std::distance(start
,end
);
219 /// Find the dimension along which to bisect the bounding box
220 int maxSpreadDim
= findMaxSpreadDimension(start
,end
);
221 /// Pin the location of the 1/3 and 2/3 elements
222 Iterator oneThird
= start
;
223 std::advance(oneThird
,numVertices
/3);
224 Iterator twoThird
= oneThird
;
225 std::advance(twoThird
,numVertices
/3);
226 /// Trisect the vertex list at the median element
227 std::nth_element( start
, oneThird
, end
, lessThan(maxSpreadDim
) );
228 std::nth_element( oneThird
, twoThird
, end
, lessThan(maxSpreadDim
) );
229 /// Partition the three pieces further
230 int numLeft
= numPartitions
/3;
231 partition(parent
, start
, oneThird
, numLeft
);
232 partition(parent
, oneThird
, twoThird
, numLeft
);
233 partition(parent
, twoThird
, end
, numLeft
);
235 /// else simply call partition to let it handle things
237 partition(parent
, start
, end
, numPartitions
);
242 template <typename Iterator
>
243 int TreeBoundingBoxOn3dTorus
<Iterator
>::findMaxSpreadDimension(const Iterator start
, const Iterator end
)
245 int nDims
= (*start
).X
.size();
246 std::vector
<int> min
, max
, spread
;
249 spread
.reserve(nDims
);
250 /// Find the min and max coordinates along each dimension of the bounding box
251 min
= max
= (*start
).X
;
252 for (Iterator itr
= start
; itr
!= end
; itr
++)
254 /// @todo: Assert that the dimensions of the coordinate vectors of the this vertex are the same as the parent's
255 for (int i
=0; i
<nDims
; i
++)
257 if ( (*itr
).X
[i
] < min
[i
] )
258 min
[i
] = (*itr
).X
[i
];
259 if ( (*itr
).X
[i
] > max
[i
] )
260 max
[i
] = (*itr
).X
[i
];
263 /// Identify the dimension of the maximum spread in coordinates
264 int maxSpread
= abs(max
[0] - min
[0]);
265 int maxSpreadDimension
= 0;
266 for (int i
=1; i
<nDims
; i
++)
268 int spread
= abs(max
[i
] - min
[i
]);
269 if (maxSpread
< spread
)
272 maxSpreadDimension
= i
;
275 return maxSpreadDimension
;
278 } // end namespace impl
280 } // end namespace topo
281 #endif // TREE_STRATEGY_3D_TORUS_MIN_HOPS