13 #ifndef ZOLTAN2_IMBALANCEMETRICSUTILITY_HPP
14 #define ZOLTAN2_IMBALANCEMETRICSUTILITY_HPP
64 template <
typename scalar_t,
typename lno_t,
typename part_t>
66 const RCP<const Environment> &env,
67 const RCP<
const Comm<int> > &comm,
68 const ArrayView<const part_t> &part,
76 ArrayRCP<scalar_t> &globalSums)
82 numExistingParts = numNonemptyParts = 0;
85 if (vwgtDim) numMetrics++;
86 if (vwgtDim > 1) numMetrics += vwgtDim;
88 auto next = metrics.size();
90 for(
int n = 0; n < numMetrics; ++n) {
91 RCP<im_t> newMetric = addNewMetric<im_t, scalar_t>(env, metrics);
101 lno_t localNumObj = part.size();
102 part_t localNum[2], globalNum[2];
103 localNum[0] =
static_cast<part_t>(vwgtDim);
106 for (
lno_t i=0; i < localNumObj; i++)
107 if (part[i] > localNum[1]) localNum[1] = part[i];
110 reduceAll<int, part_t>(*comm, Teuchos::REDUCE_MAX, 2,
111 localNum, globalNum);
115 env->globalBugAssertion(__FILE__,__LINE__,
116 "inconsistent number of vertex weights",
119 part_t maxPartPlusOne = globalNum[1] + 1;
122 part_t globalSumSize = maxPartPlusOne * numMetrics;
124 scalar_t * sumBuf =
new scalar_t[globalSumSize];
125 env->localMemoryAssertion(__FILE__, __LINE__, globalSumSize, sumBuf);
126 globalSums = arcp(sumBuf, 0, globalSumSize);
131 scalar_t *localBuf =
new scalar_t[globalSumSize];
132 env->localMemoryAssertion(__FILE__, __LINE__, globalSumSize, localBuf);
133 memset(localBuf, 0,
sizeof(scalar_t) * globalSumSize);
135 scalar_t *obj = localBuf;
137 for (
lno_t i=0; i < localNumObj; i++)
142 scalar_t *wgt = localBuf+maxPartPlusOne;
144 normedPartWeights<scalar_t, lno_t, part_t>(env, maxPartPlusOne,
145 part, vwgts, mcNorm, wgt);
152 wgt += maxPartPlusOne;
153 for (
int vdim = 0; vdim < vwgtDim; vdim++){
154 for (
lno_t i=0; i < localNumObj; i++)
155 wgt[part[i]] += vwgts[vdim][i];
156 wgt += maxPartPlusOne;
162 metrics[next]->setName(
"object count");
163 metrics[next]->setMetricValue(
"local sum", localNumObj);
168 scalar_t *wgt = localBuf+maxPartPlusOne;
169 scalar_t total = 0.0;
171 for (
int p=0; p < maxPartPlusOne; p++){
176 metrics[next]->setName(
"weight 0");
178 metrics[next]->setName(
"normed weight");
180 metrics[next]->setMetricValue(
"local sum", total);
185 for (
int vdim = 0; vdim < vwgtDim; vdim++){
186 wgt += maxPartPlusOne;
188 for (
int p=0; p < maxPartPlusOne; p++){
192 std::ostringstream oss;
193 oss <<
"weight " << vdim;
195 metrics[next]->setName(oss.str());
196 metrics[next]->setMetricValue(
"local sum", total);
207 reduceAll<int, scalar_t>(*comm, Teuchos::REDUCE_SUM, globalSumSize,
218 scalar_t min=0, max=0, sum=0;
219 next = metrics.size() - numMetrics;
225 ArrayView<scalar_t> objVec(obj, maxPartPlusOne);
226 getStridedStats<scalar_t>(objVec, 1, 0, min, max, sum);
227 if (maxPartPlusOne < targetNumParts)
230 metrics[next]->setMetricValue(
"global minimum", min);
231 metrics[next]->setMetricValue(
"global maximum", max);
232 metrics[next]->setMetricValue(
"global sum", sum);
236 scalar_t *wgt = sumBuf + maxPartPlusOne;
238 ArrayView<scalar_t> normedWVec(wgt, maxPartPlusOne);
239 getStridedStats<scalar_t>(normedWVec, 1, 0, min, max, sum);
240 if (maxPartPlusOne < targetNumParts)
243 metrics[next]->setMetricValue(
"global minimum", min);
244 metrics[next]->setMetricValue(
"global maximum", max);
245 metrics[next]->setMetricValue(
"global sum", sum);
249 for (
int vdim=0; vdim < vwgtDim; vdim++){
250 wgt += maxPartPlusOne;
251 ArrayView<scalar_t> fromVec(wgt, maxPartPlusOne);
252 getStridedStats<scalar_t>(fromVec, 1, 0, min, max, sum);
253 if (maxPartPlusOne < targetNumParts)
256 metrics[next]->setMetricValue(
"global minimum", min);
257 metrics[next]->setMetricValue(
"global maximum", max);
258 metrics[next]->setMetricValue(
"global sum", sum);
267 numExistingParts = maxPartPlusOne;
275 numNonemptyParts = numExistingParts;
277 for (
part_t p=0; p < numExistingParts; p++)
278 if (obj[p] == 0) numNonemptyParts--;
313 template <
typename Adapter>
315 const RCP<const Environment> &env,
316 const RCP<
const Comm<int> > &comm,
320 const ArrayView<const typename Adapter::part_t> &partArray,
328 typedef typename Adapter::scalar_t scalar_t;
337 size_t numLocalObjects = ia->getLocalNumIDs();
341 int nWeights = ia->getNumWeightsPerID();
342 int numCriteria = (nWeights > 0 ? nWeights : 1);
343 Array<sdata_t>
weights(numCriteria);
348 weights[0] = sdata_t();
353 bool useDegreeAsWeight =
false;
357 useDegreeAsWeight(0);
361 useDegreeAsWeight(0);
365 useDegreeAsWeight(0);
367 if (useDegreeAsWeight) {
368 ArrayView<const gno_t> Ids;
369 ArrayView<sdata_t> vwgts;
370 RCP<GraphModel<base_adapter_t> > graph;
371 if (graphModel == Teuchos::null) {
372 std::bitset<NUM_MODEL_FLAGS> modelFlags;
373 const RCP<const base_adapter_t> bia =
374 rcp(dynamic_cast<const base_adapter_t *>(ia),
false);
376 graph->getVertexList(Ids, vwgts);
378 graphModel->getVertexList(Ids, vwgts);
380 scalar_t *wgt =
new scalar_t[numLocalObjects];
381 for (
int i=0; i < nWeights; i++){
382 for (
size_t j=0; j < numLocalObjects; j++) {
383 wgt[j] = vwgts[i][j];
385 ArrayRCP<const scalar_t> wgtArray(wgt,0,numLocalObjects,
false);
386 weights[i] = sdata_t(wgtArray, 1);
389 for (
int i=0; i < nWeights; i++){
392 ia->getWeightsView(wgt, stride, i);
393 ArrayRCP<const scalar_t> wgtArray(wgt,0,stride*numLocalObjects,
false);
394 weights[i] = sdata_t(wgtArray, stride);
401 part_t targetNumParts = comm->getSize();
402 scalar_t *psizes = NULL;
404 ArrayRCP<ArrayRCP<scalar_t> > partSizes(numCriteria);
407 for (
int dim=0; dim < numCriteria; dim++){
409 psizes =
new scalar_t [targetNumParts];
410 env->localMemoryAssertion(__FILE__, __LINE__, targetNumParts, psizes);
411 for (part_t i=0; i < targetNumParts; i++){
414 partSizes[dim] = arcp(psizes, 0, targetNumParts,
true);
423 ArrayRCP<scalar_t> globalSums;
425 int initialMetricCount = metrics.size();
427 globalSumsByPart<scalar_t, lno_t, part_t>(env, comm,
428 partArray, nWeights, weights.view(0, numCriteria), mcNorm,
429 targetNumParts, numExistingParts, numNonemptyParts, metrics, globalSums);
433 int addedMetricsCount = metrics.size() - initialMetricCount;
439 int index = initialMetricCount;
441 scalar_t *objCount = globalSums.getRawPtr();
442 scalar_t min, max, avg;
445 if (partSizes[0].size() > 0)
446 psizes = partSizes[0].getRawPtr();
448 scalar_t gsum = metrics[index]->getMetricValue(
"global sum");
449 computeImbalances<scalar_t, part_t>(numExistingParts, targetNumParts, psizes,
450 gsum, objCount, min, max, avg);
452 metrics[index]->setMetricValue(
"global average", gsum / targetNumParts);
454 metrics[index]->setMetricValue(
"maximum imbalance", 1.0 + max);
455 metrics[index]->setMetricValue(
"average imbalance", avg);
460 scalar_t *wgts = globalSums.getRawPtr() + numExistingParts;
462 if (addedMetricsCount > 1){
464 gsum = metrics[index]->getMetricValue(
"global sum");
465 computeImbalances<scalar_t, part_t>(numExistingParts, targetNumParts,
466 numCriteria, partSizes.view(0, numCriteria), gsum, wgts, min, max, avg);
468 metrics[index]->setMetricValue(
"global average", gsum / targetNumParts);
470 metrics[index]->setMetricValue(
"maximum imbalance", 1.0 + max);
471 metrics[index]->setMetricValue(
"average imbalance", avg);
473 if (addedMetricsCount > 2){
480 for (
int vdim=0; vdim < numCriteria; vdim++){
481 wgts += numExistingParts;
484 if (partSizes[vdim].size() > 0)
485 psizes = partSizes[vdim].getRawPtr();
487 gsum = metrics[index]->getMetricValue(
"global sum");
488 computeImbalances<scalar_t, part_t>(numExistingParts, targetNumParts,
489 psizes, gsum, wgts, min, max, avg);
491 metrics[index]->setMetricValue(
"global average", gsum / targetNumParts);
493 metrics[index]->setMetricValue(
"maximum imbalance", 1.0 + max);
494 metrics[index]->setMetricValue(
"average imbalance", avg);
505 template <
typename scalar_t,
typename part_t>
512 os <<
"Imbalance Metrics: (" << numExistingParts <<
" existing parts)";
513 if (numNonemptyParts < numExistingParts) {
514 os <<
" (" << numNonemptyParts <<
" of which are non-empty)";
517 if (targetNumParts != numExistingParts) {
518 os <<
"Target number of parts is " << targetNumParts << std::endl;
525 template <
typename scalar_t,
typename part_t>
533 printImbalanceMetricsHeader<scalar_t, part_t>(os, targetNumParts,
536 for (
int i=0; i < infoList.size(); i++) {
538 infoList[i]->printLine(os);
546 template <
typename scalar_t,
typename part_t>
554 printImbalanceMetricsHeader<scalar_t, part_t>(os, targetNumParts,
557 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.
map_t::global_ordinal_type gno_t
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.
map_t::local_ordinal_type lno_t
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