Zoltan2
Toggle main menu visibility
Loading...
Searching...
No Matches
Zoltan2_MetricUtility.hpp
Go to the documentation of this file.
1
// @HEADER
2
//
3
// ***********************************************************************
4
//
5
// Zoltan2: A package of combinatorial algorithms for scientific computing
6
// Copyright 2012 Sandia Corporation
7
//
8
// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
9
// the U.S. Government retains certain rights in this software.
10
//
11
// Redistribution and use in source and binary forms, with or without
12
// modification, are permitted provided that the following conditions are
13
// met:
14
//
15
// 1. Redistributions of source code must retain the above copyright
16
// notice, this list of conditions and the following disclaimer.
17
//
18
// 2. Redistributions in binary form must reproduce the above copyright
19
// notice, this list of conditions and the following disclaimer in the
20
// documentation and/or other materials provided with the distribution.
21
//
22
// 3. Neither the name of the Corporation nor the names of the
23
// contributors may be used to endorse or promote products derived from
24
// this software without specific prior written permission.
25
//
26
// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
27
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
30
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
31
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
32
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
33
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
34
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
35
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
36
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37
//
38
// Questions? Contact Karen Devine (kddevin@sandia.gov)
39
// Erik Boman (egboman@sandia.gov)
40
// Siva Rajamanickam (srajama@sandia.gov)
41
//
42
// ***********************************************************************
43
//
44
// @HEADER
45
49
50
#ifndef ZOLTAN2_METRICFUNCTIONS_HPP
51
#define ZOLTAN2_METRICFUNCTIONS_HPP
52
53
#include <
Zoltan2_StridedData.hpp
>
54
55
namespace
Zoltan2
{
56
57
// this utlity method is used to allocate more metrics in the metric array
58
// the array is composed of an array of ptrs to BaseClassMetric
59
// but each ptr is allocated to the specific derived metric type
60
// So the array can access the polymorphic hierarchy
61
//
62
// Note this is currently only relevant to EvaluatePartition and the
63
// GraphMetrics and ImbalanceMetrics calculations
64
template
<
typename
metric_t,
typename
scalar_t>
65
RCP<metric_t>
addNewMetric
(
const
RCP<const Environment> &env,
66
ArrayRCP<RCP<
BaseClassMetrics<scalar_t>
> > &metrics)
67
{
68
metrics.resize(metrics.size() + 1);
// increase array size by 1
69
metric_t * newMetric =
new
metric_t;
// allocate
70
env->localMemoryAssertion(__FILE__,__LINE__,1,newMetric);
// check errors
71
RCP<metric_t> newRCP = rcp(newMetric);
// rcp of derived class
72
metrics[metrics.size()-1] = newRCP;
// create the new rcp
73
return
newRCP;
74
}
75
77
// Namespace methods to compute metric values
79
89
template
<
typename
scalar_t>
90
void
getStridedStats
(
const
ArrayView<scalar_t> &v,
int
stride,
91
int
offset,
scalar_t
&min,
scalar_t
&max,
scalar_t
&sum)
92
{
93
if
(v.size() < 1)
return
;
94
min = max = sum = v[offset];
95
96
for
(
int
i=offset+stride; i < v.size(); i += stride){
97
if
(v[i] < min) min = v[i];
98
else
if
(v[i] > max) max = v[i];
99
sum += v[i];
100
}
101
}
102
111
template
<
typename
scalar_t>
112
void
getStridedStats
(
const
ArrayView<scalar_t> &v,
int
stride,
113
int
offset,
scalar_t
&max,
scalar_t
&sum)
114
{
115
if
(v.size() < 1)
return
;
116
max = sum = v[offset];
117
118
for
(
int
i=offset+stride; i < v.size(); i += stride){
119
if
(v[i] > max) max = v[i];
120
sum += v[i];
121
}
122
}
123
141
142
template
<
typename
scalar_t,
typename
lno_t,
typename
part_t>
143
void
normedPartWeights
(
144
const
RCP<const Environment> &env,
145
part_t
numberOfParts,
146
const
ArrayView<const part_t> &parts,
147
const
ArrayView<
StridedData<lno_t, scalar_t>
> &vwgts,
148
multiCriteriaNorm
mcNorm,
149
scalar_t
*weights)
150
{
151
env->localInputAssertion(__FILE__, __LINE__,
"parts or weights"
,
152
numberOfParts > 0 && vwgts.size() > 0,
BASIC_ASSERTION
);
153
154
int
numObjects = parts.size();
155
int
vwgtDim = vwgts.size();
156
157
memset(weights, 0,
sizeof
(
scalar_t
) * numberOfParts);
158
159
if
(numObjects == 0)
160
return
;
161
162
if
(vwgtDim == 0) {
163
for
(
lno_t
i=0; i < numObjects; i++){
164
weights[parts[i]]++;
165
}
166
}
167
else
if
(vwgtDim == 1){
168
for
(
lno_t
i=0; i < numObjects; i++){
169
weights[parts[i]] += vwgts[0][i];
170
}
171
}
172
else
{
173
switch
(mcNorm){
174
case
normMinimizeTotalWeight
:
175
for
(
int
wdim=0; wdim < vwgtDim; wdim++){
176
for
(
lno_t
i=0; i < numObjects; i++){
177
weights[parts[i]] += vwgts[wdim][i];
178
}
179
}
// next weight index
180
break
;
181
182
case
normBalanceTotalMaximum
:
183
for
(
lno_t
i=0; i < numObjects; i++){
184
scalar_t
ssum = 0;
185
for
(
int
wdim=0; wdim < vwgtDim; wdim++)
186
ssum += (vwgts[wdim][i] * vwgts[wdim][i]);
187
weights[parts[i]] += sqrt(ssum);
188
}
189
break
;
190
191
case
normMinimizeMaximumWeight
:
192
for
(
lno_t
i=0; i < numObjects; i++){
193
scalar_t
max = 0;
194
for
(
int
wdim=0; wdim < vwgtDim; wdim++)
195
if
(vwgts[wdim][i] > max)
196
max = vwgts[wdim][i];
197
weights[parts[i]] += max;
198
}
199
break
;
200
201
default
:
202
env->localBugAssertion(__FILE__, __LINE__,
"invalid norm"
,
false
,
203
BASIC_ASSERTION
);
204
break
;
205
}
206
}
207
}
208
238
239
template
<
typename
scalar_t,
typename
part_t>
240
void
computeImbalances
(
241
part_t
numExistingParts,
// Max Part ID + 1
242
part_t
targetNumParts,
// comm.size() or requested global # parts from soln
243
const
scalar_t
*psizes,
244
scalar_t
sumVals,
245
const
scalar_t
*vals,
246
scalar_t
&min,
247
scalar_t
&max,
248
scalar_t
&avg)
249
{
250
min = sumVals;
251
max = avg = 0;
252
253
if
(sumVals <= 0 || targetNumParts < 1 || numExistingParts < 1)
254
return
;
255
256
if
(targetNumParts==1) {
257
min = max = avg = 0;
// 0 imbalance
258
return
;
259
}
260
261
if
(!psizes){
262
scalar_t
target = sumVals / targetNumParts;
263
for
(
part_t
p=0; p < numExistingParts; p++){
264
scalar_t
diff = vals[p] - target;
265
scalar_t
adiff = (diff >= 0 ? diff : -diff);
266
scalar_t
tmp = diff / target;
267
scalar_t
atmp = adiff / target;
268
avg += atmp;
269
if
(tmp > max) max = tmp;
270
if
(tmp < min) min = tmp;
271
}
272
part_t
emptyParts = targetNumParts - numExistingParts;
273
if
(emptyParts > 0){
274
if
(max < 1.0)
275
max = 1.0;
// target divided by target
276
avg += emptyParts;
277
}
278
}
279
else
{
280
for
(
part_t
p=0; p < targetNumParts; p++){
281
if
(psizes[p] > 0){
282
if
(p < numExistingParts){
283
scalar_t
target = sumVals * psizes[p];
284
scalar_t
diff = vals[p] - target;
285
scalar_t
adiff = (diff >= 0 ? diff : -diff);
286
scalar_t
tmp = diff / target;
287
scalar_t
atmp = adiff / target;
288
avg += atmp;
289
if
(tmp > max) max = tmp;
290
if
(tmp < min) min = tmp;
291
}
292
else
{
293
if
(max < 1.0)
294
max = 1.0;
// target divided by target
295
avg += 1.0;
296
}
297
}
298
}
299
}
300
301
avg /= targetNumParts;
302
}
303
336
337
template
<
typename
scalar_t,
typename
part_t>
338
void
computeImbalances
(
339
part_t
numExistingParts,
340
part_t
targetNumParts,
341
int
numSizes,
342
ArrayView<ArrayRCP<scalar_t> > psizes,
343
scalar_t
sumVals,
344
const
scalar_t
*vals,
345
scalar_t
&min,
346
scalar_t
&max,
347
scalar_t
&avg)
348
{
349
min = sumVals;
350
max = avg = 0;
351
352
if
(sumVals <= 0 || targetNumParts < 1 || numExistingParts < 1)
353
return
;
354
355
if
(targetNumParts==1) {
356
min = max = avg = 0;
// 0 imbalance
357
return
;
358
}
359
360
bool
allUniformParts =
true
;
361
for
(
int
i=0; i < numSizes; i++){
362
if
(psizes[i].size() != 0){
363
allUniformParts =
false
;
364
break
;
365
}
366
}
367
368
if
(allUniformParts){
369
computeImbalances<scalar_t, part_t>
(numExistingParts, targetNumParts, NULL,
370
sumVals, vals, min, max, avg);
371
return
;
372
}
373
374
double
uniformSize = 1.0 / targetNumParts;
375
std::vector<double> sizeVec(numSizes);
376
for
(
int
i=0; i < numSizes; i++){
377
sizeVec[i] = uniformSize;
378
}
379
380
for
(
part_t
p=0; p < numExistingParts; p++){
381
382
// If we have objects in parts that should have 0 objects,
383
// we don't compute an imbalance. It means that other
384
// parts have too few objects, and the imbalance will be
385
// picked up there.
386
387
if
(p >= targetNumParts)
388
break
;
389
390
// Vector of target amounts: T
391
392
double
targetNorm = 0;
393
for
(
int
i=0; i < numSizes; i++) {
394
if
(psizes[i].size() > 0)
395
sizeVec[i] = psizes[i][p];
396
sizeVec[i] *= sumVals;
397
targetNorm += (sizeVec[i] * sizeVec[i]);
398
}
399
targetNorm = sqrt(targetNorm);
400
401
// If part is supposed to be empty, we don't compute an
402
// imbalance. Same argument as above.
403
404
if
(targetNorm > 0){
405
406
// Vector of actual amounts: A
407
408
std::vector<double> actual(numSizes);
409
double
actualNorm = 0.;
410
for
(
int
i=0; i < numSizes; i++) {
411
actual[i] = vals[p] * -1.0;
412
actual[i] += sizeVec[i];
413
actualNorm += (actual[i] * actual[i]);
414
}
415
actualNorm = sqrt(actualNorm);
416
417
// |A - T| / |T|
418
419
scalar_t
imbalance = actualNorm / targetNorm;
420
421
if
(imbalance < min)
422
min = imbalance;
423
else
if
(imbalance > max)
424
max = imbalance;
425
avg += imbalance;
426
}
427
}
428
429
part_t
numEmptyParts = 0;
430
431
for
(
part_t
p=numExistingParts; p < targetNumParts; p++){
432
bool
nonEmptyPart =
false
;
433
for
(
int
i=0; !nonEmptyPart && i < numSizes; i++)
434
if
(psizes[i].size() > 0 && psizes[i][p] > 0.0)
435
nonEmptyPart =
true
;
436
437
if
(nonEmptyPart){
438
// The partition has no objects for this part, which
439
// is supposed to be non-empty.
440
numEmptyParts++;
441
}
442
}
443
444
if
(numEmptyParts > 0){
445
avg += numEmptyParts;
446
if
(max < 1.0)
447
max = 1.0;
// target divided by target
448
}
449
450
avg /= targetNumParts;
451
}
452
455
template
<
typename
scalar_t>
456
scalar_t
normedWeight
(ArrayView <scalar_t> weights,
457
multiCriteriaNorm
norm)
458
{
459
size_t
dim = weights.size();
460
if
(dim == 0)
461
return
0.0;
462
else
if
(dim == 1)
463
return
weights[0];
464
465
scalar_t
nweight = 0;
466
467
switch
(norm){
468
case
normMinimizeTotalWeight
:
469
470
for
(
size_t
i=0; i <dim; i++)
471
nweight += weights[i];
472
473
break
;
474
475
case
normBalanceTotalMaximum
:
476
for
(
size_t
i=0; i <dim; i++)
477
nweight += (weights[i] * weights[i]);
478
479
nweight = sqrt(nweight);
480
481
break
;
482
483
case
normMinimizeMaximumWeight
:
484
485
nweight = weights[0];
486
for
(
size_t
i=1; i <dim; i++)
487
if
(weights[i] > nweight)
488
nweight = weights[i];
489
490
break
;
491
492
default
:
493
std::ostringstream emsg;
494
emsg << __FILE__ <<
":"
<< __LINE__ << std::endl;
495
emsg <<
"bug: "
<<
"invalid norm"
<< std::endl;
496
throw
std::logic_error(emsg.str());
497
}
498
499
return
nweight;
500
}
501
504
template
<
typename
lno_t,
typename
scalar_t>
505
scalar_t
normedWeight
(ArrayView<
StridedData<lno_t, scalar_t>
> weights,
506
lno_t
idx,
multiCriteriaNorm
norm)
507
{
508
size_t
dim = weights.size();
509
if
(dim < 1)
510
return
0;
511
512
Array<scalar_t> vec(dim, 1.0);
513
for
(
size_t
i=0; i < dim; i++)
514
if
(weights[i].size() > 0)
515
vec[dim] = weights[i][idx];
516
517
return
normedWeight
(vec, norm);
518
}
519
520
}
//namespace Zoltan2
521
522
#endif
Zoltan2_StridedData.hpp
This file defines the StridedData class.
Zoltan2::BaseClassMetrics
Definition
Zoltan2_BaseClassMetrics.hpp:62
Zoltan2::StridedData
The StridedData class manages lists of weights or coordinates.
Definition
Zoltan2_StridedData.hpp:76
Zoltan2
Created by mbenlioglu on Aug 31, 2020.
Definition
Zoltan2_AlgHybrid2GL.hpp:38
Zoltan2::computeImbalances
void computeImbalances(part_t numExistingParts, part_t targetNumParts, const scalar_t *psizes, scalar_t sumVals, const scalar_t *vals, scalar_t &min, scalar_t &max, scalar_t &avg)
Compute the imbalance.
Definition
Zoltan2_MetricUtility.hpp:240
Zoltan2::normedPartWeights
void normedPartWeights(const RCP< const Environment > &env, part_t numberOfParts, const ArrayView< const part_t > &parts, const ArrayView< StridedData< lno_t, scalar_t > > &vwgts, multiCriteriaNorm mcNorm, scalar_t *weights)
Compute the total weight in each part on this process.
Definition
Zoltan2_MetricUtility.hpp:143
Zoltan2::getStridedStats
void getStridedStats(const ArrayView< scalar_t > &v, int stride, int offset, scalar_t &min, scalar_t &max, scalar_t &sum)
Find min, max and sum of metric values.
Definition
Zoltan2_MetricUtility.hpp:90
Zoltan2::addNewMetric
RCP< metric_t > addNewMetric(const RCP< const Environment > &env, ArrayRCP< RCP< BaseClassMetrics< scalar_t > > > &metrics)
Definition
Zoltan2_MetricUtility.hpp:65
Zoltan2::normedWeight
scalar_t normedWeight(ArrayView< scalar_t > weights, multiCriteriaNorm norm)
Compute the norm of the vector of weights.
Definition
Zoltan2_MetricUtility.hpp:456
Zoltan2::BASIC_ASSERTION
@ BASIC_ASSERTION
fast typical checks for valid arguments
Definition
Zoltan2_Parameters.hpp:83
Zoltan2::multiCriteriaNorm
multiCriteriaNorm
Enumerator used in code for multicriteria norm choice.
Definition
Zoltan2_Parameters.hpp:139
Zoltan2::normBalanceTotalMaximum
@ normBalanceTotalMaximum
Definition
Zoltan2_Parameters.hpp:141
Zoltan2::normMinimizeTotalWeight
@ normMinimizeTotalWeight
Definition
Zoltan2_Parameters.hpp:140
Zoltan2::normMinimizeMaximumWeight
@ normMinimizeMaximumWeight
Definition
Zoltan2_Parameters.hpp:142
Zoltan2::scalar_t
core
src
util
Zoltan2_MetricUtility.hpp
Generated by
1.18.0