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;
392 useDegreeAsWeight(0);
396 useDegreeAsWeight(0);
400 useDegreeAsWeight(0);
402 if (useDegreeAsWeight) {
403 ArrayView<const gno_t> Ids;
404 ArrayView<sdata_t> vwgts;
405 RCP<GraphModel<base_adapter_t> > graph;
406 if (graphModel == Teuchos::null) {
407 std::bitset<NUM_MODEL_FLAGS> modelFlags;
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
scalar_t getCriteriaPartSize(int idx, part_t part) const
Get the size for a given weight index and a given part.
#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
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.
A PartitioningSolution is a solution to a partitioning problem.
static void printHeader(std::ostream &os)
Print a standard header.
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.
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.
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.
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.
#define METRICS_UNSET_STRING
Zoltan2::BasicUserTypes< zscalar_t, zlno_t, zgno_t > user_t