49 #ifndef ZOLTAN2_IMBALANCEMETRICSUTILITY_HPP 50 #define ZOLTAN2_IMBALANCEMETRICSUTILITY_HPP 100 template <
typename scalar_t,
typename lno_t,
typename part_t>
102 const RCP<const Environment> &env,
103 const RCP<
const Comm<int> > &comm,
104 const ArrayView<const part_t> &part,
112 ArrayRCP<scalar_t> &globalSums)
118 numExistingParts = numNonemptyParts = 0;
121 if (vwgtDim) numMetrics++;
122 if (vwgtDim > 1) numMetrics += vwgtDim;
124 auto next = metrics.size();
126 for(
int n = 0; n < numMetrics; ++n) {
127 RCP<im_t> newMetric = addNewMetric<im_t, scalar_t>(env, metrics);
137 lno_t localNumObj = part.size();
138 part_t localNum[2], globalNum[2];
139 localNum[0] =
static_cast<part_t>(vwgtDim);
142 for (lno_t i=0; i < localNumObj; i++)
143 if (part[i] > localNum[1]) localNum[1] = part[i];
146 reduceAll<int, part_t>(*comm, Teuchos::REDUCE_MAX, 2,
147 localNum, globalNum);
151 env->globalBugAssertion(__FILE__,__LINE__,
152 "inconsistent number of vertex weights",
155 part_t maxPartPlusOne = globalNum[1] + 1;
158 part_t globalSumSize = maxPartPlusOne * numMetrics;
159 scalar_t * sumBuf =
new scalar_t [globalSumSize];
160 env->localMemoryAssertion(__FILE__, __LINE__, globalSumSize, sumBuf);
161 globalSums = arcp(sumBuf, 0, globalSumSize);
166 scalar_t *localBuf =
new scalar_t [globalSumSize];
167 env->localMemoryAssertion(__FILE__, __LINE__, globalSumSize, localBuf);
168 memset(localBuf, 0,
sizeof(scalar_t) * globalSumSize);
170 scalar_t *obj = localBuf;
172 for (lno_t i=0; i < localNumObj; i++)
177 scalar_t *wgt = localBuf+maxPartPlusOne;
179 normedPartWeights<scalar_t, lno_t, part_t>(env, maxPartPlusOne,
180 part, vwgts, mcNorm, wgt);
187 wgt += maxPartPlusOne;
188 for (
int vdim = 0; vdim < vwgtDim; vdim++){
189 for (lno_t i=0; i < localNumObj; i++)
190 wgt[part[i]] += vwgts[vdim][i];
191 wgt += maxPartPlusOne;
197 metrics[next]->setName(
"object count");
198 metrics[next]->setMetricValue(
"local sum", localNumObj);
203 scalar_t *wgt = localBuf+maxPartPlusOne;
204 scalar_t total = 0.0;
206 for (
int p=0; p < maxPartPlusOne; p++){
211 metrics[next]->setName(
"weight 0");
213 metrics[next]->setName(
"normed weight");
215 metrics[next]->setMetricValue(
"local sum", total);
220 for (
int vdim = 0; vdim < vwgtDim; vdim++){
221 wgt += maxPartPlusOne;
223 for (
int p=0; p < maxPartPlusOne; p++){
227 std::ostringstream oss;
228 oss <<
"weight " << vdim;
230 metrics[next]->setName(oss.str());
231 metrics[next]->setMetricValue(
"local sum", total);
242 reduceAll<int, scalar_t>(*comm, Teuchos::REDUCE_SUM, globalSumSize,
253 scalar_t min=0, max=0, sum=0;
254 next = metrics.size() - numMetrics;
260 ArrayView<scalar_t> objVec(obj, maxPartPlusOne);
261 getStridedStats<scalar_t>(objVec, 1, 0, min, max, sum);
262 if (maxPartPlusOne < targetNumParts)
265 metrics[next]->setMetricValue(
"global minimum", min);
266 metrics[next]->setMetricValue(
"global maximum", max);
267 metrics[next]->setMetricValue(
"global sum", sum);
271 scalar_t *wgt = sumBuf + maxPartPlusOne;
273 ArrayView<scalar_t> normedWVec(wgt, maxPartPlusOne);
274 getStridedStats<scalar_t>(normedWVec, 1, 0, min, max, sum);
275 if (maxPartPlusOne < targetNumParts)
278 metrics[next]->setMetricValue(
"global minimum", min);
279 metrics[next]->setMetricValue(
"global maximum", max);
280 metrics[next]->setMetricValue(
"global sum", sum);
284 for (
int vdim=0; vdim < vwgtDim; vdim++){
285 wgt += maxPartPlusOne;
286 ArrayView<scalar_t> fromVec(wgt, maxPartPlusOne);
287 getStridedStats<scalar_t>(fromVec, 1, 0, min, max, sum);
288 if (maxPartPlusOne < targetNumParts)
291 metrics[next]->setMetricValue(
"global minimum", min);
292 metrics[next]->setMetricValue(
"global maximum", max);
293 metrics[next]->setMetricValue(
"global sum", sum);
302 numExistingParts = maxPartPlusOne;
310 numNonemptyParts = numExistingParts;
312 for (
part_t p=0; p < numExistingParts; p++)
313 if (obj[p] == 0) numNonemptyParts--;
348 template <
typename Adapter>
350 const RCP<const Environment> &env,
351 const RCP<
const Comm<int> > &comm,
355 const ArrayView<const typename Adapter::part_t> &partArray,
363 typedef typename Adapter::scalar_t scalar_t;
364 typedef typename Adapter::gno_t gno_t;
365 typedef typename Adapter::lno_t lno_t;
372 size_t numLocalObjects = ia->getLocalNumIDs();
376 int nWeights = ia->getNumWeightsPerID();
377 int numCriteria = (nWeights > 0 ? nWeights : 1);
378 Array<sdata_t>
weights(numCriteria);
383 weights[0] = sdata_t();
388 bool useDegreeAsWeight =
false;
391 <typename Adapter::user_t, typename Adapter::userCoord_t
> *>(ia)->
392 useDegreeAsWeight(0);
395 <typename Adapter::user_t, typename Adapter::userCoord_t
> *>(ia)->
396 useDegreeAsWeight(0);
400 useDegreeAsWeight(0);
402 if (useDegreeAsWeight) {
403 ArrayView<const gno_t> Ids;
404 ArrayView<sdata_t> vwgts;
405 if (graphModel == Teuchos::null) {
406 std::bitset<NUM_MODEL_FLAGS> modelFlags;
407 RCP<GraphModel<base_adapter_t> > graph;
408 const RCP<const base_adapter_t> bia =
409 rcp(dynamic_cast<const base_adapter_t *>(ia),
false);
411 graph->getVertexList(Ids, vwgts);
413 graphModel->getVertexList(Ids, vwgts);
415 scalar_t *wgt =
new scalar_t[numLocalObjects];
416 for (
int i=0; i < nWeights; i++){
417 for (
size_t j=0; j < numLocalObjects; j++) {
418 wgt[j] = vwgts[i][j];
420 ArrayRCP<const scalar_t> wgtArray(wgt,0,numLocalObjects,
false);
421 weights[i] = sdata_t(wgtArray, 1);
424 for (
int i=0; i < nWeights; i++){
427 ia->getWeightsView(wgt, stride, i);
428 ArrayRCP<const scalar_t> wgtArray(wgt,0,stride*numLocalObjects,
false);
429 weights[i] = sdata_t(wgtArray, stride);
436 part_t targetNumParts = comm->getSize();
437 scalar_t *psizes = NULL;
439 ArrayRCP<ArrayRCP<scalar_t> > partSizes(numCriteria);
442 for (
int dim=0; dim < numCriteria; dim++){
444 psizes =
new scalar_t [targetNumParts];
445 env->localMemoryAssertion(__FILE__, __LINE__, targetNumParts, psizes);
446 for (part_t i=0; i < targetNumParts; i++){
449 partSizes[dim] = arcp(psizes, 0, targetNumParts,
true);
458 ArrayRCP<scalar_t> globalSums;
460 int initialMetricCount = metrics.size();
462 globalSumsByPart<scalar_t, lno_t, part_t>(env, comm,
463 partArray, nWeights, weights.view(0, numCriteria), mcNorm,
464 targetNumParts, numExistingParts, numNonemptyParts, metrics, globalSums);
468 int addedMetricsCount = metrics.size() - initialMetricCount;
474 int index = initialMetricCount;
476 scalar_t *objCount = globalSums.getRawPtr();
477 scalar_t min, max, avg;
480 if (partSizes[0].size() > 0)
481 psizes = partSizes[0].getRawPtr();
483 scalar_t gsum = metrics[index]->getMetricValue(
"global sum");
484 computeImbalances<scalar_t, part_t>(numExistingParts, targetNumParts, psizes,
485 gsum, objCount, min, max, avg);
487 metrics[index]->setMetricValue(
"global average", gsum / targetNumParts);
489 metrics[index]->setMetricValue(
"maximum imbalance", 1.0 + max);
490 metrics[index]->setMetricValue(
"average imbalance", avg);
495 scalar_t *wgts = globalSums.getRawPtr() + numExistingParts;
497 if (addedMetricsCount > 1){
499 gsum = metrics[index]->getMetricValue(
"global sum");
500 computeImbalances<scalar_t, part_t>(numExistingParts, targetNumParts,
501 numCriteria, partSizes.view(0, numCriteria), gsum, wgts, min, max, avg);
503 metrics[index]->setMetricValue(
"global average", gsum / targetNumParts);
505 metrics[index]->setMetricValue(
"maximum imbalance", 1.0 + max);
506 metrics[index]->setMetricValue(
"average imbalance", avg);
508 if (addedMetricsCount > 2){
515 for (
int vdim=0; vdim < numCriteria; vdim++){
516 wgts += numExistingParts;
519 if (partSizes[vdim].size() > 0)
520 psizes = partSizes[vdim].getRawPtr();
522 gsum = metrics[index]->getMetricValue(
"global sum");
523 computeImbalances<scalar_t, part_t>(numExistingParts, targetNumParts,
524 psizes, gsum, wgts, min, max, avg);
526 metrics[index]->setMetricValue(
"global average", gsum / targetNumParts);
528 metrics[index]->setMetricValue(
"maximum imbalance", 1.0 + max);
529 metrics[index]->setMetricValue(
"average imbalance", avg);
540 template <
typename scalar_t,
typename part_t>
547 os <<
"Imbalance Metrics: (" << numExistingParts <<
" existing parts)";
548 if (numNonemptyParts < numExistingParts) {
549 os <<
" (" << numNonemptyParts <<
" of which are non-empty)";
552 if (targetNumParts != numExistingParts) {
553 os <<
"Target number of parts is " << targetNumParts << std::endl;
560 template <
typename scalar_t,
typename part_t>
568 printImbalanceMetricsHeader<scalar_t, part_t>(os, targetNumParts,
571 for (
int i=0; i < infoList.size(); i++) {
573 infoList[i]->printLine(os);
581 template <
typename scalar_t,
typename part_t>
589 printImbalanceMetricsHeader<scalar_t, part_t>(os, targetNumParts,
592 metricValue->printLine(os);
void imbalanceMetrics(const RCP< const Environment > &env, const RCP< const Comm< int > > &comm, multiCriteriaNorm mcNorm, const Adapter *ia, const PartitioningSolution< Adapter > *solution, const ArrayView< const typename Adapter::part_t > &partArray, const RCP< const GraphModel< typename Adapter::base_adapter_t > > &graphModel, typename Adapter::part_t &numExistingParts, typename Adapter::part_t &numNonemptyParts, ArrayRCP< RCP< BaseClassMetrics< typename Adapter::scalar_t > > > &metrics)
Compute imbalance metrics for a distribution.
Zoltan2::BaseAdapter< userTypes_t > base_adapter_t
#define Z2_FORWARD_EXCEPTIONS
Forward an exception back through call stack.
MatrixAdapter defines the adapter interface for matrices.
GraphAdapter defines the interface for graph-based user data.
MeshAdapter defines the interface for mesh input.
sub-steps, each method's entry and exit
SparseMatrixAdapter_t::part_t part_t
A PartitioningSolution is a solution to a partitioning problem.
static void printHeader(std::ostream &os)
Print a standard header.
scalar_t getCriteriaPartSize(int idx, part_t part) const
Get the size for a given weight index and a given part.
BaseAdapterType
An enum to identify general types of adapters.
The StridedData class manages lists of weights or coordinates.
void setNorm(multiCriteriaNorm normVal)
Set or reset the norm.
void printImbalanceMetrics(std::ostream &os, part_t targetNumParts, part_t numExistingParts, part_t numNonemptyParts, const ArrayView< RCP< BaseClassMetrics< scalar_t >>> &infoList)
Print out list of imbalance metrics.
GraphModel defines the interface required for graph models.
multiCriteriaNorm
Enumerator used in code for multicriteria norm choice.
void globalSumsByPart(const RCP< const Environment > &env, const RCP< const Comm< int > > &comm, const ArrayView< const part_t > &part, int vwgtDim, const ArrayView< StridedData< lno_t, scalar_t > > &vwgts, multiCriteriaNorm mcNorm, part_t targetNumParts, part_t &numExistingParts, part_t &numNonemptyParts, ArrayRCP< RCP< BaseClassMetrics< scalar_t > > > &metrics, ArrayRCP< scalar_t > &globalSums)
Given the local partitioning, compute the global sums in each part.
bool criteriaHasUniformPartSizes(int idx) const
Determine if balancing criteria has uniform part sizes. (User can specify differing part sizes...
size_t getTargetGlobalNumberOfParts() const
Returns the global number of parts desired in the solution.
void printImbalanceMetricsHeader(std::ostream &os, part_t targetNumParts, part_t numExistingParts, part_t numNonemptyParts)
Print out header info for imbalance metrics.
#define Z2_THROW_OUTSIDE_ERROR(env)
Throw an error returned from outside the Zoltan2 library.
#define METRICS_UNSET_STRING