|
Zoltan2
|
00001 // @HEADER 00002 // 00003 // *********************************************************************** 00004 // 00005 // Zoltan2: A package of combinatorial algorithms for scientific computing 00006 // Copyright 2012 Sandia Corporation 00007 // 00008 // Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, 00009 // the U.S. Government retains certain rights in this software. 00010 // 00011 // Redistribution and use in source and binary forms, with or without 00012 // modification, are permitted provided that the following conditions are 00013 // met: 00014 // 00015 // 1. Redistributions of source code must retain the above copyright 00016 // notice, this list of conditions and the following disclaimer. 00017 // 00018 // 2. Redistributions in binary form must reproduce the above copyright 00019 // notice, this list of conditions and the following disclaimer in the 00020 // documentation and/or other materials provided with the distribution. 00021 // 00022 // 3. Neither the name of the Corporation nor the names of the 00023 // contributors may be used to endorse or promote products derived from 00024 // this software without specific prior written permission. 00025 // 00026 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY 00027 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 00028 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 00029 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE 00030 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 00031 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 00032 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 00033 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 00034 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 00035 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 00036 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00037 // 00038 // Questions? Contact Karen Devine (kddevin@sandia.gov) 00039 // Erik Boman (egboman@sandia.gov) 00040 // Siva Rajamanickam (srajama@sandia.gov) 00041 // 00042 // *********************************************************************** 00043 // 00044 // @HEADER 00045 00050 #ifndef _ZOLTAN2_ALGRCB_METHODS_HPP_ 00051 #define _ZOLTAN2_ALGRCB_METHODS_HPP_ 00052 00053 #include <Zoltan2_PartitioningSolution.hpp> 00054 #include <Zoltan2_XpetraTraits.hpp> 00055 #include <Zoltan2_Metric.hpp> 00056 00057 #include <Tpetra_Vector.hpp> 00058 00059 #include <sstream> 00060 #include <string> 00061 #include <cmath> 00062 #include <bitset> 00063 00064 #include <Teuchos_DataAccess.hpp> 00065 00066 namespace Teuchos{ 00067 00074 template <typename Ordinal, typename T> 00075 class Zoltan2_RCBOperation : public ValueTypeReductionOp<Ordinal,T> 00076 { 00077 private: 00078 Ordinal numSum_, numMin_, numMax_; 00079 00080 public: 00083 Zoltan2_RCBOperation():numSum_(0), numMin_(0), numMax_(0){} 00084 00091 Zoltan2_RCBOperation(Ordinal nsum, Ordinal nmin, Ordinal nmax): 00092 numSum_(nsum), numMin_(nmin), numMax_(nmax){} 00093 00096 void reduce( const Ordinal count, const T inBuffer[], T inoutBuffer[]) const 00097 { 00098 Ordinal next=0; 00099 for (Ordinal i=0; i < numSum_; i++, next++) 00100 inoutBuffer[next] += inBuffer[next]; 00101 00102 for (Ordinal i=0; i < numMin_; i++, next++) 00103 if (inoutBuffer[next] > inBuffer[next]) 00104 inoutBuffer[next] = inBuffer[next]; 00105 00106 for (Ordinal i=0; i < numMax_; i++, next++) 00107 if (inoutBuffer[next] < inBuffer[next]) 00108 inoutBuffer[next] = inBuffer[next]; 00109 } 00110 00113 ArrayRCP<T> getInitializedBuffer(T minExtreme, T maxExtreme) const 00114 { 00115 Ordinal len = numSum_+numMin_+numMax_; 00116 T *buf = new T [len]; 00117 if (!buf) 00118 throw std::bad_alloc(); 00119 00120 Ordinal next=0; 00121 for (Ordinal i=0; i < numSum_; i++) 00122 buf[next++] = 0; 00123 for (Ordinal i=0; i < numMin_; i++) 00124 buf[next++] = minExtreme; 00125 for (Ordinal i=0; i < numMax_; i++) 00126 buf[next++] = maxExtreme; 00127 00128 ArrayRCP<T> returnBuf = arcp(buf, 0, len, true); 00129 return returnBuf; 00130 } 00131 }; 00132 } // namespace Teuchos 00133 00134 namespace Zoltan2{ 00135 00138 enum rcbParams { 00139 rcb_balanceCount, 00140 rcb_balanceWeight, 00141 rcb_minTotalWeight, 00142 rcb_minMaximumWeight, 00143 rcb_balanceTotalMaximum, 00144 rcb_averageCuts, 00145 rcb_rectilinear, 00146 rcb_multiplePartSizeSpecs, 00147 NUM_RCB_PARAMS 00148 }; 00149 00157 enum leftRightFlag{ 00158 unsetFlag = 0xfd, 00159 leftFlag = 0xfe, 00160 rightFlag = 0xff 00161 }; 00162 00163 // TODO: RCB has several helper methods. 00164 // Do we want a convention for naming algorithm methods? Do 00165 // we want sub-namespaces for algorithms? 00166 00180 template <typename Adapter> 00181 void getFractionLeft( 00182 const RCP<const Environment> &env, 00183 typename Adapter::part_t part0, 00184 typename Adapter::part_t part1, 00185 const RCP<PartitioningSolution<Adapter> > &solution, 00186 ArrayRCP<double> &fractionLeft, 00187 typename Adapter::part_t &numPartsLeftHalf) 00188 { 00189 env->debug(DETAILED_STATUS, "Entering getFractionLeft"); 00190 00191 typedef typename Adapter::part_t part_t; 00192 00193 part_t numParts = part1 - part0 + 1; 00194 // TODO In LDRD, substitute call to machine model for 00195 // TODO computation of numPartsLeftHalf below. 00196 numPartsLeftHalf = numParts / 2; 00197 part_t left0 = part0; // First part in left half 00198 part_t left1 = left0 + numPartsLeftHalf - 1; // Last part in left half 00199 part_t right0 = left1 + 1; // First part in right half 00200 part_t right1 = part1; // Last part in right half 00201 00202 int nVecs = solution->getNumberOfCriteria(); 00203 fractionLeft = arcp(new double [nVecs], 0, nVecs); 00204 00205 for (int widx=0; widx<nVecs; widx++){ 00206 if (solution->criteriaHasUniformPartSizes(widx)){ 00207 fractionLeft[widx] = double(numPartsLeftHalf) / double(numParts); 00208 } 00209 else{ 00210 fractionLeft[widx] = 0; 00211 for(int partId=left0; partId <= left1; partId++){ 00212 fractionLeft[widx] += solution->getCriteriaPartSize(widx, partId); 00213 } 00214 double total = fractionLeft[widx]; 00215 for(int partId=right0; partId <= right1; partId++){ 00216 total += solution->getCriteriaPartSize(widx, partId); 00217 } 00218 fractionLeft[widx] /= total; 00219 } 00220 } 00221 env->debug(DETAILED_STATUS, "Exiting getFractionLeft"); 00222 } 00223 00242 template <typename mvector_t> 00243 void getCutDimension( 00244 const RCP<const Environment> &env, 00245 const RCP<Comm<int> > &comm, 00246 int coordDim, 00247 const RCP<mvector_t> &vectors, 00248 ArrayView<typename mvector_t::local_ordinal_type> index, 00249 int &dimension, // output 00250 typename mvector_t::scalar_type &minCoord, // output 00251 typename mvector_t::scalar_type &maxCoord) // output 00252 { 00253 env->debug(DETAILED_STATUS, "Entering getCutDimension"); 00254 typedef typename mvector_t::scalar_type scalar_t; 00255 typedef typename mvector_t::local_ordinal_type lno_t; 00256 00257 int nprocs = comm->getSize(); 00258 bool useIndices = index.size() > 0; 00259 lno_t numLocalCoords = 0; 00260 00261 if (useIndices) 00262 numLocalCoords = index.size(); 00263 else 00264 numLocalCoords = vectors->getLocalLength(); 00265 00266 Array<scalar_t> spans(coordDim*2); 00267 int next = 0; 00268 00269 if (useIndices){ 00270 if (numLocalCoords > 0){ 00271 for (int dim=0; dim < coordDim; dim++){ 00272 const scalar_t *val = vectors->getData(dim).getRawPtr(); 00273 scalar_t v = val[index[0]]; 00274 scalar_t min = v; 00275 scalar_t max = v; 00276 for (lno_t i=1; i < numLocalCoords; i++){ 00277 v = val[index[i]]; 00278 if (v > max) 00279 max = v; 00280 else if (v < min) 00281 min = v; 00282 } 00283 00284 spans[next++] = min; 00285 spans[next++] = max * -1.0; 00286 } 00287 } 00288 else{ 00289 for (int dim=0; dim < coordDim; dim++){ 00290 spans[next++] = std::numeric_limits<scalar_t>::max(); 00291 spans[next++] = std::numeric_limits<scalar_t>::min() * -1.0; 00292 } 00293 } 00294 } 00295 else{ 00296 for (int dim=0; dim < coordDim; dim++){ 00297 const scalar_t *val = vectors->getData(dim).getRawPtr(); 00298 std::pair<scalar_t, scalar_t> minMax = 00299 z2LocalMinMax<scalar_t>(val, numLocalCoords); 00300 spans[next++] = minMax.first; 00301 spans[next++] = minMax.second * -1.0; 00302 } 00303 } 00304 00305 if (nprocs > 1){ 00306 Array<scalar_t> globalValues(coordDim*2); 00307 try{ 00308 reduceAll<int, scalar_t>(*comm, Teuchos::REDUCE_MIN, coordDim*2, 00309 spans.getRawPtr(), globalValues.getRawPtr()); 00310 } 00311 Z2_THROW_OUTSIDE_ERROR(*env) 00312 00313 for (int i=0; i < coordDim*2; i++) 00314 spans[i] = globalValues[i]; 00315 } 00316 00317 scalar_t maxSpan = 0; 00318 dimension = -1; 00319 next = 0; 00320 00321 for (int dim=0; dim < coordDim; dim++){ 00322 scalar_t min = spans[next++]; 00323 scalar_t max = spans[next++] * -1.0; 00324 scalar_t newSpan = max - min; 00325 if (newSpan > maxSpan){ 00326 maxSpan = newSpan; 00327 dimension = dim; 00328 minCoord = min; 00329 maxCoord = max; 00330 } 00331 } 00332 env->debug(DETAILED_STATUS, "Exiting getCutDimension"); 00333 } 00334 00351 template <typename mvector_t> 00352 void migrateData( 00353 const RCP<const Environment> &env, const RCP<Comm<int> > &comm, 00354 ArrayView<unsigned char> lrflags, 00355 RCP<mvector_t> &vectors, // on return is the new data 00356 int &leftNumProcs) // on return is num procs with left data 00357 { 00358 env->debug(DETAILED_STATUS, "Entering migrateData"); 00359 typedef typename mvector_t::scalar_type scalar_t; 00360 typedef typename mvector_t::local_ordinal_type lno_t; 00361 typedef typename mvector_t::global_ordinal_type gno_t; 00362 00363 int nprocs = comm->getSize(); 00364 size_t nobj = vectors->getLocalLength(); 00365 size_t nGlobalObj = vectors->getGlobalLength(); 00366 00367 env->localBugAssertion(__FILE__, __LINE__, "migrateData input", 00368 nprocs>1 && size_t(lrflags.size())==nobj, DEBUG_MODE_ASSERTION); 00369 00370 gno_t myNumLeft= 0, numLeft; 00371 for (size_t i=0; i < nobj; i++) 00372 if (lrflags[i] == leftFlag) 00373 myNumLeft++; 00374 00375 try{ 00376 reduceAll<int, gno_t>( 00377 *comm, Teuchos::REDUCE_SUM, 1, &myNumLeft, &numLeft); 00378 } 00379 Z2_THROW_OUTSIDE_ERROR(*env) 00380 00381 scalar_t leftFraction = scalar_t(numLeft)/scalar_t(nGlobalObj); 00382 leftNumProcs = static_cast<int>(floor((nprocs*leftFraction)+.5)); 00383 00384 if (leftNumProcs == 0) 00385 leftNumProcs++; 00386 else if (leftNumProcs == nprocs) 00387 leftNumProcs--; 00388 00390 // Get a list of my new global numbers. 00391 00392 Array<int> sendCount(nprocs, 0); 00393 Array<int> recvCount(nprocs, 0); 00394 Array<gno_t> sendBuf(nobj, 0); 00395 00396 if (nobj > 0){ 00397 int *procId = new int [nobj]; 00398 env->localMemoryAssertion(__FILE__, __LINE__, nobj, procId) ; 00399 int leftProc0 = 0; 00400 int rightProc0 = leftProc0 + leftNumProcs; 00401 00402 int nextLeftProc = leftProc0; 00403 int nextRightProc = rightProc0; 00404 int *p = procId; 00405 00406 for (size_t i=0; i < nobj; i++){ 00407 if (lrflags[i] == leftFlag){ 00408 if (nextLeftProc == rightProc0) 00409 nextLeftProc = leftProc0; 00410 00411 sendCount[nextLeftProc]++; 00412 *p++ = nextLeftProc++; 00413 } 00414 else{ 00415 if (nextRightProc == nprocs) 00416 nextRightProc = rightProc0; 00417 sendCount[nextRightProc]++; 00418 00419 *p++ = nextRightProc++; 00420 } 00421 } 00422 00423 gno_t *sendOffset = new gno_t [nprocs]; 00424 env->localMemoryAssertion(__FILE__, __LINE__, nprocs, sendOffset) ; 00425 sendOffset[0] = 0; 00426 for (int i=0; i < nprocs-1; i++) 00427 sendOffset[i+1] = sendOffset[i] + sendCount[i]; 00428 00429 ArrayView<const gno_t> gnoList = vectors->getMap()->getNodeElementList(); 00430 00431 for (size_t i=0; i < nobj; i++){ 00432 int proc = procId[i]; 00433 lno_t offset = sendOffset[proc]++; 00434 00435 sendBuf[offset] = gnoList[i]; 00436 } 00437 00438 delete [] sendOffset; 00439 delete [] procId; 00440 } 00441 00442 ArrayRCP<gno_t> recvBuf; 00443 00444 try{ 00445 AlltoAllv<gno_t>(*comm, *env, 00446 sendBuf(), sendCount(), 00447 recvBuf, recvCount()); 00448 } 00449 Z2_FORWARD_EXCEPTIONS 00450 00451 sendCount.clear(); 00452 sendBuf.clear(); 00453 00455 // Migrate the multivector of data. 00456 00457 gno_t numMyNewGnos = 0; 00458 for (int i=0; i < nprocs; i++) 00459 numMyNewGnos += recvCount[i]; 00460 00461 recvCount.clear(); 00462 00463 RCP<const mvector_t> newMultiVector; 00464 RCP<const mvector_t> constInput = rcp_const_cast<const mvector_t>(vectors); 00465 00466 try{ 00467 newMultiVector = XpetraTraits<mvector_t>::doMigration( 00468 constInput, numMyNewGnos, recvBuf.getRawPtr()); 00469 } 00470 Z2_FORWARD_EXCEPTIONS 00471 00472 vectors = rcp_const_cast<mvector_t>(newMultiVector); 00473 env->memory("Former problem data replaced with new data"); 00474 env->debug(DETAILED_STATUS, "Exiting migrateData"); 00475 } 00476 00477 template <typename lno_t, typename scalar_t> 00478 scalar_t getCoordWeight(lno_t id, 00479 multiCriteriaNorm mcnorm, 00480 ArrayView<StridedData<lno_t, scalar_t> > weights) 00481 { 00482 scalar_t wgtValue = 1.0; 00483 size_t nWeightsPerCoord = weights.size(); 00484 00485 if (nWeightsPerCoord > 1){ 00486 Array<scalar_t> coordWeights(nWeightsPerCoord, 1.0); 00487 for (size_t widx=0; widx < nWeightsPerCoord; widx++){ 00488 coordWeights[widx] = weights[widx][id]; 00489 } 00490 00491 wgtValue = normedWeight<scalar_t>(coordWeights.view(0,nWeightsPerCoord), mcnorm); 00492 } 00493 else if (nWeightsPerCoord > 0){ 00494 wgtValue = weights[0][id]; 00495 } 00496 00497 return wgtValue; 00498 } 00499 00517 template <typename scalar_t> 00518 bool emptyPartsCheck( const RCP<const Environment> &env, 00519 const ArrayView<double> fractionLeft, 00520 scalar_t minCoord, scalar_t maxCoord, 00521 leftRightFlag &lrf, 00522 scalar_t &cutValue) 00523 { 00524 env->debug(DETAILED_STATUS, "Entering emptyPartsCheck"); 00525 // initialize return values 00526 lrf = leftFlag; 00527 cutValue = 0.0; 00528 00529 size_t nVecs = fractionLeft.size(); 00530 int numEmptyRight = 0, numEmptyLeft = 0; 00531 00532 for (size_t i=0; i < nVecs; i++){ 00533 if (fractionLeft[i] == 0.0) 00534 numEmptyLeft++; 00535 else if (fractionLeft[i] == 1.0) 00536 numEmptyRight++; 00537 } 00538 00539 if (numEmptyRight + numEmptyLeft == 0) 00540 return false; 00541 00542 env->localInputAssertion(__FILE__, __LINE__, 00543 "partitioning not solvable - conflicting part size criteria", 00544 (numEmptyRight==0) || (numEmptyLeft==0), BASIC_ASSERTION); 00545 00546 if (numEmptyLeft > 0){ 00547 lrf = leftFlag; 00548 cutValue = minCoord; 00549 } 00550 else{ 00551 lrf = rightFlag; 00552 cutValue = maxCoord; 00553 } 00554 00555 env->debug(DETAILED_STATUS, "Exiting emptyPartsCheck"); 00556 return true; 00557 } 00558 00571 template <typename lno_t, typename gno_t, typename scalar_t> 00572 void testCoordinatesOnRightBoundary( 00573 const RCP<const Environment> &env, 00574 const RCP<Comm<int> > &comm, 00575 scalar_t totalWeightLeft, 00576 scalar_t targetLeftScalar, 00577 int cutLocation, 00578 ArrayView<scalar_t> localSums, 00579 ArrayView<scalar_t> globalSums, 00580 ArrayView<lno_t> index, 00581 ArrayView<StridedData<lno_t, scalar_t> > weights, 00582 multiCriteriaNorm mcnorm, 00583 ArrayView<unsigned char> lrFlags, 00584 scalar_t &globalWeightMovedRight) // output 00585 { 00586 env->debug(DETAILED_STATUS, "Entering testCoordinatesOnRightBoundary"); 00587 int nprocs = comm->getSize(); 00588 int rank = comm->getRank(); 00589 00590 globalWeightMovedRight = 0.0; 00591 00592 scalar_t localBoundarySum = localSums[cutLocation]; 00593 00594 scalar_t total = totalWeightLeft; 00595 for (int i=0; i <= cutLocation; i++) 00596 total += globalSums[i]; 00597 00598 scalar_t totalMoveRight = total - targetLeftScalar; 00599 scalar_t localMoveRight = localBoundarySum; 00600 scalar_t actualWeightMovedRight = 0.0; 00601 00602 Array<scalar_t> scansum(nprocs+1, 0.0); 00603 Teuchos::gatherAll<int, scalar_t>(*comm, 1, 00604 &localBoundarySum, nprocs, scansum.getRawPtr()+1); 00605 for (int i=2; i<=nprocs; i++) 00606 scansum[i] += scansum[i-1]; 00607 00608 if (localBoundarySum > 0.0){ 00609 00610 scalar_t sumMine = scansum[rank]; // sum of ranks preceding me 00611 scalar_t diff = scansum[nprocs] - sumMine; 00612 localMoveRight = 0; 00613 00614 if (diff <= totalMoveRight) 00615 localMoveRight = localBoundarySum; // all 00616 else{ 00617 scalar_t leftPart = diff - totalMoveRight; 00618 if (leftPart < localBoundarySum) 00619 localMoveRight = localBoundarySum - leftPart; 00620 } 00621 } 00622 00623 if (localMoveRight > 0.0){ 00624 00625 bool moveAll = (localMoveRight >= localBoundarySum); 00626 00627 if (moveAll){ 00628 actualWeightMovedRight = localBoundarySum; 00629 for (lno_t i=0; i < lrFlags.size(); i++){ 00630 if (lrFlags[i] == cutLocation){ 00631 lrFlags[i] = rightFlag; 00632 } 00633 } 00634 } 00635 else{ 00636 int nWeightsPerCoord = weights.size(); 00637 int useIndices = index.size() > 0; 00638 00639 for (lno_t i=0; i < lrFlags.size(); i++){ 00640 if (lrFlags[i] == cutLocation){ 00641 lrFlags[i] = rightFlag; 00642 00643 lno_t idx = (useIndices ? index[i] : i); 00644 00645 actualWeightMovedRight += getCoordWeight<lno_t, scalar_t>( 00646 idx, mcnorm, weights.view(0, nWeightsPerCoord)); 00647 00648 if (actualWeightMovedRight >= localMoveRight) 00649 break; 00650 } 00651 } // next coordinate 00652 } 00653 } 00654 00655 try{ 00656 reduceAll<int, scalar_t>( 00657 *comm, Teuchos::REDUCE_SUM, 1, &actualWeightMovedRight, 00658 &globalWeightMovedRight); 00659 } 00660 Z2_THROW_OUTSIDE_ERROR(*env) 00661 00662 env->debug(DETAILED_STATUS, "Exiting testCoordinatesOnRightBoundary"); 00663 return; 00664 } 00665 00712 template <typename mvector_t> 00713 void BSPfindCut( 00714 const RCP<const Environment> &env, 00715 const RCP<Comm<int> > &comm, 00716 const std::bitset<NUM_RCB_PARAMS> ¶ms, 00717 int numTestCuts, 00718 typename mvector_t::scalar_type tolerance, 00719 int cutDim, 00720 int coordDim, 00721 int nWeightsPerCoord, 00722 const RCP<mvector_t> &vectors, 00723 ArrayView<typename mvector_t::local_ordinal_type> index, 00724 ArrayView<double> fractionLeft, 00725 typename mvector_t::scalar_type coordGlobalMin, 00726 typename mvector_t::scalar_type coordGlobalMax, 00727 typename mvector_t::scalar_type &cutValue, // output 00728 ArrayView<unsigned char> lrFlags, // output 00729 typename mvector_t::scalar_type &totalWeightLeft, // output 00730 typename mvector_t::scalar_type &totalWeightRight, // output 00731 typename mvector_t::local_ordinal_type &localCountLeft, // output 00732 typename mvector_t::scalar_type &imbalance) // output 00733 { 00734 env->debug(DETAILED_STATUS, "Entering BSPfindCut"); 00735 00736 // initialize output 00737 bool useIndices = index.size() > 0; 00738 int numAllCoords = vectors->getLocalLength(); 00739 int numCoords = (useIndices ? index.size() : numAllCoords); 00740 cutValue = totalWeightLeft = totalWeightRight = imbalance = 0.0; 00741 localCountLeft = 0; 00742 00743 for (int i=0; i < numCoords; i++) 00744 lrFlags[i] = unsetFlag; 00745 00746 typedef typename mvector_t::scalar_type scalar_t; 00747 typedef typename mvector_t::local_ordinal_type lno_t; 00748 typedef typename mvector_t::global_ordinal_type gno_t; 00749 typedef StridedData<lno_t, scalar_t> input_t; 00750 00751 bool multiplePartSizeSpecs = params.test(rcb_multiplePartSizeSpecs); 00752 bool rectilinear = params.test(rcb_rectilinear); 00753 bool averageCuts = params.test(rcb_averageCuts); 00754 00755 // A coordinate is considered to be on a cut if it is within 00756 // this distance of the cut. 00757 00758 double epsilon = (coordGlobalMax - coordGlobalMin) * 10e-9; 00759 00760 // Find the coordinate values and weights. 00761 00762 int nVecs = fractionLeft.size(); 00763 00764 if (env->getDebugLevel() >= DETAILED_STATUS){ 00765 std::ostringstream info; 00766 info << "Num weights " << nWeightsPerCoord << ", Fraction left:"; 00767 for (int i=0; i < nVecs; i++) 00768 info << " " << fractionLeft[i]; 00769 info << endl << "Dimension " << cutDim << " ["; 00770 info << coordGlobalMin << ", " << coordGlobalMax << "]"; 00771 info << endl << "# test cuts " << numTestCuts; 00772 info << ", tolerance " << tolerance << std::endl; 00773 env->debug(DETAILED_STATUS, info.str()); 00774 } 00775 00776 const scalar_t *coordValue = vectors->getData(cutDim).getRawPtr(); 00777 00778 input_t *wgtinfo = new input_t [nWeightsPerCoord]; 00779 env->localMemoryAssertion(__FILE__, __LINE__, nWeightsPerCoord, wgtinfo); 00780 ArrayRCP<input_t> weight(wgtinfo, 0, nWeightsPerCoord, true); 00781 00782 for (int widx = 0, cidx=coordDim; widx < nWeightsPerCoord; widx++){ 00783 weight[widx] = input_t(vectors->getData(cidx++), 1); 00784 } 00785 00786 // Multicriteria norm 00787 00788 multiCriteriaNorm mcnorm = normBalanceTotalMaximum; 00789 00790 if (params.test(rcb_minMaximumWeight)) 00791 mcnorm = normMinimizeMaximumWeight; 00792 else if (params.test(rcb_minTotalWeight)) 00793 mcnorm = normMinimizeTotalWeight; 00794 00795 // Goal is globally find one cut that comes close to leaving 00796 // partSizeLeft*totalWeight on the left side. 00797 00798 Epetra_SerialDenseVector partSizeLeft(::Teuchos::View, fractionLeft.getRawPtr(), nVecs); 00799 00800 // Where do we make the first test cuts? 00801 // 00802 // min 1 2 3 max 00803 // 00804 // Space is [min, max]. 00805 // If there are three test cuts: 1, 2 and 3. 00806 // 4 regions: [min,1] [1,2] [2,3] [3,max]. 00807 // 5 boundaries: min, 1, 2, 3, and max. 00808 00809 int numRegions = numTestCuts + 1; 00810 int numBoundaries = numTestCuts + 2; 00811 int endBoundary = numBoundaries - 1; 00812 std::vector<scalar_t> boundaries(numBoundaries); 00813 std::vector<scalar_t> searchBoundaries(numBoundaries); 00814 00815 int numSums = numBoundaries+numRegions; 00816 00817 Teuchos::Zoltan2_RCBOperation<int, scalar_t> reductionOp( 00818 numSums, // number of sums 00819 numRegions, // number of mins 00820 numRegions); // number of maxes 00821 00822 typename std::vector<scalar_t>::iterator foundCut; 00823 00824 bool done=false; 00825 bool fail=false; 00826 scalar_t min = coordGlobalMin; 00827 scalar_t max = coordGlobalMax; 00828 lno_t numRemaining = numCoords; 00829 lno_t prevNumRemaining = numCoords; 00830 size_t numGlobalPoints = vectors->getGlobalLength(); 00831 size_t sanityCheck = numGlobalPoints; 00832 00833 double totalWeight = 0; 00834 double targetLeftScalar = 0; 00835 double targetLeftNorm = 0; 00836 Epetra_SerialDenseVector targetLeftVector(nVecs); 00837 00838 while (!done && !fail && sanityCheck--){ 00839 00840 // Create regions into which coordinates will be placed. 00841 scalar_t diff = (max - min) / numRegions; 00842 boundaries[0] = min; 00843 boundaries[endBoundary] = max; 00844 for (int i=0; i < endBoundary; i++){ 00845 searchBoundaries[i+1] = boundaries[i+1] = boundaries[i] + diff; 00846 } 00847 00848 // Move ends slightly so we catch points on boundary. 00849 searchBoundaries[0] = min - epsilon; 00850 searchBoundaries[endBoundary] = max + epsilon; 00851 00852 // Save region and boundary sums, and region min and max. 00853 00854 ArrayRCP<scalar_t> localSums = reductionOp.getInitializedBuffer( 00855 searchBoundaries[endBoundary], searchBoundaries[0]); 00856 00857 ArrayRCP<scalar_t> globalSums = reductionOp.getInitializedBuffer( 00858 searchBoundaries[endBoundary], searchBoundaries[0]); 00859 00860 scalar_t *sums = localSums.getRawPtr(); 00861 scalar_t *regionMin = sums + numSums; 00862 scalar_t *regionMax = regionMin + numRegions; 00863 00864 if (numRemaining > 0){ 00865 00866 // Assign each of my points to a region. 00867 // lower_bound() finds the first cut f, such that f >= coordValue[i]. 00868 // So for now, objects that are on the cut boundary go into the 00869 // region on the "left" side. 00870 00871 for (lno_t i=0; i < numCoords; i++){ 00872 00873 if (lrFlags[i] != unsetFlag) 00874 continue; 00875 00876 int inRegion = 0; 00877 int idx = (useIndices ? index[i] : i); 00878 scalar_t value = coordValue[idx]; 00879 00880 if (numRegions > 2){ 00881 00882 foundCut = std::lower_bound( 00883 searchBoundaries.begin(), searchBoundaries.end(), value); 00884 00885 env->localBugAssertion(__FILE__, __LINE__, "search cuts", 00886 foundCut != searchBoundaries.end(), BASIC_ASSERTION); 00887 00888 inRegion = foundCut - searchBoundaries.begin() - 1; 00889 } 00890 else{ 00891 if (value <= boundaries[1]) 00892 inRegion = 0; 00893 else 00894 inRegion = 1; 00895 } 00896 00897 int sumIdx = 1 + inRegion*2; 00898 00899 if (value >= boundaries[inRegion+1]-epsilon){ 00900 // "on" right boundary of this region 00901 sumIdx++; 00902 } 00903 else if (inRegion==0 && (value < min + epsilon)){ 00904 // in region 0 but far left boundary 00905 sumIdx--; 00906 } 00907 00908 lrFlags[i] = (unsigned char)sumIdx; 00909 00910 if (value < regionMin[inRegion]) 00911 regionMin[inRegion] = value; 00912 if (value > regionMax[inRegion]) 00913 regionMax[inRegion] = value; 00914 00915 sums[sumIdx] += getCoordWeight<lno_t, scalar_t>(idx, 00916 mcnorm, weight.view(0, nWeightsPerCoord)); 00917 00918 } // next coord 00919 } 00920 00921 try{ 00922 reduceAll<int, scalar_t>(*comm, reductionOp, 00923 localSums.size(), localSums.getRawPtr(), globalSums.getRawPtr()); 00924 } 00925 Z2_THROW_OUTSIDE_ERROR(*env) 00926 00927 sums = globalSums.getRawPtr(); 00928 regionMin = sums + numSums; 00929 regionMax = regionMin + numRegions; 00930 00931 if (env->getDebugLevel() >= DETAILED_STATUS){ 00932 std::ostringstream info; 00933 info << " Region " << min << " - " << max << std::endl; 00934 info << " Remaining to classify: " << numRemaining << std::endl; 00935 info << " Boundaries: "; 00936 for (int i=0; i < numBoundaries; i++) 00937 info << boundaries[i] << " "; 00938 info << endl << " For searching: "; 00939 for (int i=0; i < numBoundaries; i++) 00940 info << searchBoundaries[i] << " "; 00941 info << endl << " Global sums: "; 00942 double sumTotal=0; 00943 for (int i=0; i < numSums; i++){ 00944 sumTotal += sums[i]; 00945 info << sums[i] << " "; 00946 } 00947 info << " total: " << sumTotal << endl; 00948 env->debug(DETAILED_STATUS, info.str()); 00949 } 00950 00951 if (totalWeight == 0){ // first time through only 00952 00953 for (int i=0; i < numSums; i++) 00954 totalWeight += sums[i]; 00955 00956 partSizeLeft.Scale(totalWeight); 00957 targetLeftVector = partSizeLeft; 00958 00959 targetLeftScalar = targetLeftVector[0]; 00960 targetLeftNorm = targetLeftVector.Norm2(); 00961 totalWeightLeft = 0; 00962 totalWeightRight = 0; 00963 } 00964 00965 int cutLocation=0; 00966 scalar_t testDiff=0, prevTestDiff=0, target=0; 00967 00968 if (multiplePartSizeSpecs){ 00969 // more complex: if we have multiple weights 00970 // and the part sizes requested 00971 // for each weight index differ, then we may not 00972 // be able to reach the imbalance tolerance. 00973 // 00974 // TODO: discuss how to (or whether to) handle this case. 00975 // 00976 // For now we look at this imbalance: 00977 // 00978 // |target - actual|^2 / |target|^2 00979 00980 target = targetLeftNorm; 00981 Epetra_SerialDenseVector testVec(nVecs); 00982 for (int i=0; i < nVecs; i++) 00983 testVec[i] = totalWeightLeft; 00984 Epetra_SerialDenseVector diffVec = testVec; 00985 diffVec.Scale(-1.0); 00986 diffVec += targetLeftVector; 00987 00988 testDiff = diffVec.Norm2(); // imbalance numerator 00989 prevTestDiff = testDiff; 00990 cutLocation= -1; 00991 00992 while (++cutLocation< numSums){ 00993 00994 for (int i=0; i < nVecs; i++) 00995 testVec[i] += sums[cutLocation]; 00996 00997 diffVec = testVec; 00998 diffVec.Scale(-1.0); 00999 diffVec += targetLeftVector; 01000 01001 testDiff = diffVec.Norm2(); 01002 01003 if (testDiff >= target) 01004 break; 01005 01006 prevTestDiff = testDiff; 01007 } 01008 } 01009 else{ // the part sizes for each weight index are the same 01010 01011 target = targetLeftScalar; 01012 testDiff = totalWeightLeft; 01013 prevTestDiff = testDiff; 01014 cutLocation = -1; 01015 01016 while (++cutLocation < numSums){ 01017 01018 testDiff += sums[cutLocation]; 01019 if (testDiff >= target) 01020 break; 01021 01022 prevTestDiff = testDiff; 01023 } 01024 } 01025 01026 scalar_t diffLeftCut = target - prevTestDiff; 01027 scalar_t diffRightCut = testDiff - target; 01028 01029 if (diffLeftCut < diffRightCut){ 01030 imbalance = diffLeftCut / target; 01031 if (imbalance <= tolerance){ 01032 env->debug(DETAILED_STATUS, " Done, tolerance met"); 01033 done = true; 01034 cutLocation--; 01035 } 01036 } 01037 else{ 01038 imbalance = diffRightCut / target; 01039 if (imbalance <= tolerance){ 01040 env->debug(DETAILED_STATUS, " Done, tolerance met"); 01041 done = true; 01042 } 01043 } 01044 01045 bool cutLocIsRegion = (cutLocation % 2 == 1); 01046 bool cutLocIsBoundary = !cutLocIsRegion; 01047 01048 if (env->getDebugLevel() >= DETAILED_STATUS){ 01049 std::ostringstream info; 01050 info << " Best cut location: " << cutLocation; 01051 if (cutLocIsRegion) info << " just after a region." << std::endl; 01052 else info << " just after a boundary." << std::endl; 01053 env->debug(DETAILED_STATUS, info.str()); 01054 } 01055 01056 if (!done && cutLocIsBoundary){ 01057 01058 done = true; // can not divide space any more 01059 01060 env->debug(DETAILED_STATUS, " Done, cutting at a region boundary"); 01061 01062 if (rectilinear){ 01063 // Can not divide boundary points into two 01064 // different regions to achieve balance. 01065 fail = true; 01066 } 01067 else { 01068 // Maybe by moving some of the points right, we can 01069 // obtain a better balance. If so, the lrFlag for 01070 // the points moved right will be updated here. 01071 01072 scalar_t globalWeightMovedRight(0); 01073 01074 testCoordinatesOnRightBoundary<lno_t, gno_t, scalar_t>( 01075 env, comm, totalWeightLeft, targetLeftScalar, cutLocation, 01076 localSums.view(0, numSums), globalSums.view(0, numSums), 01077 index, weight.view(0, nWeightsPerCoord), mcnorm, lrFlags, 01078 globalWeightMovedRight); 01079 01080 scalar_t newSum = testDiff - globalWeightMovedRight; 01081 globalSums[cutLocation] -= globalWeightMovedRight; 01082 01083 if (newSum > target) 01084 imbalance = (target - newSum) / target; 01085 else 01086 imbalance = (newSum - target) / target; 01087 01088 if (imbalance > tolerance) 01089 fail = true; 01090 } 01091 } 01092 01093 int rightmostLeftNum=0, leftmostRightNum=0; 01094 01095 if (!done){ 01096 // Best cut is following a region. Narrow down the boundaries. 01097 01098 int regionNumber = (cutLocation - 1) / 2; 01099 01100 min = regionMin[regionNumber]; 01101 max = regionMax[regionNumber]; 01102 01103 rightmostLeftNum = cutLocation - 1; 01104 leftmostRightNum = cutLocation + 1; 01105 } 01106 else{ 01107 rightmostLeftNum = cutLocation; 01108 leftmostRightNum = cutLocation + 1; 01109 01110 if (cutLocIsRegion && averageCuts){ 01111 int regionNumber = (cutLocation - 1) / 2; 01112 cutValue = ( 01113 boundaries[regionNumber+1] + // boundary to right 01114 regionMax[regionNumber]) // rightmost point in region 01115 / 2.0; 01116 } 01117 } 01118 01119 for (int i=0; i <= rightmostLeftNum; i++){ 01120 totalWeightLeft += globalSums[i]; 01121 } 01122 01123 for (lno_t i=0; i < numCoords; i++){ 01124 if (lrFlags[i] != leftFlag && lrFlags[i] != rightFlag){ 01125 if (lrFlags[i] <= rightmostLeftNum){ 01126 lrFlags[i] = leftFlag; 01127 numRemaining--; 01128 localCountLeft++; 01129 } 01130 else if (lrFlags[i] >= leftmostRightNum){ 01131 lrFlags[i] = rightFlag; 01132 numRemaining--; 01133 } 01134 else{ 01135 lrFlags[i] = unsetFlag; // still to be determined 01136 } 01137 } 01138 } 01139 01140 if (env->getDebugLevel() >= VERBOSE_DETAILED_STATUS && numCoords < 100){ 01141 // For large numCoords, building this message 01142 // takes an extraordinarily long time. 01143 std::ostringstream ossLeft; 01144 std::ostringstream ossRight; 01145 ossLeft << "left: "; 01146 ossRight << "right: "; 01147 for (lno_t i=0; i < numCoords; i++){ 01148 if (lrFlags[i] == unsetFlag) 01149 continue; 01150 lno_t idx = (useIndices ? index[i] : i); 01151 scalar_t val = coordValue[idx]; 01152 if (lrFlags[i] == leftFlag) 01153 ossLeft << val << " "; 01154 else if (lrFlags[i] == rightFlag) 01155 ossRight << val << " "; 01156 else 01157 env->localBugAssertion(__FILE__, __LINE__, 01158 "left/right flags", false, BASIC_ASSERTION); 01159 } 01160 std::ostringstream msg; 01161 msg << ossLeft.str() << endl << ossRight.str() << std::endl; 01162 env->debug(VERBOSE_DETAILED_STATUS, msg.str()); 01163 } 01164 01165 prevNumRemaining = numRemaining; 01166 } // while !done 01167 01168 totalWeightRight = totalWeight - totalWeightLeft; 01169 01170 if (fail) 01171 env->debug(BASIC_STATUS, "Warning: tolerance not achieved in sub-step"); 01172 01173 // TODO: If fail the warn that tolerance was not met. 01174 01175 env->globalInputAssertion(__FILE__, __LINE__, "partitioning not solvable", 01176 done, DEBUG_MODE_ASSERTION, comm); 01177 01178 env->memory("End of bisection"); 01179 01180 if (env->getDebugLevel() >= DETAILED_STATUS){ 01181 std::ostringstream oss; 01182 oss << "Exiting BSPfindCut, "; 01183 oss << "# iterations: " << numGlobalPoints - sanityCheck; 01184 env->debug(DETAILED_STATUS, oss.str()); 01185 } 01186 01187 return; 01188 } 01189 01216 template <typename mvector_t, typename Adapter> 01217 void determineCut( 01218 const RCP<const Environment> &env, 01219 const RCP<Comm<int> > &comm, 01220 const std::bitset<NUM_RCB_PARAMS> ¶ms, 01221 int numTestCuts, 01222 typename mvector_t::scalar_type tolerance, 01223 int coordDim, 01224 int nWeightsPerCoord, 01225 const RCP<mvector_t> &vectors, 01226 multiCriteriaNorm mcnorm, 01227 const RCP<PartitioningSolution<Adapter> > &solution, 01228 typename Adapter::part_t part0, 01229 typename Adapter::part_t part1, 01230 ArrayView<unsigned char> lrflags, // output 01231 int &cutDimension, // output 01232 typename mvector_t::scalar_type &cutValue, // output 01233 typename mvector_t::scalar_type &imbalance, // output 01234 typename Adapter::part_t &numPartsLeftHalf, // output 01235 typename mvector_t::scalar_type &weightLeftHalf, // output 01236 typename mvector_t::scalar_type &weightRightHalf // output 01237 ) 01238 { 01239 env->debug(DETAILED_STATUS, "Entering determineCut"); 01240 typedef typename Adapter::part_t part_t; 01241 typedef typename mvector_t::scalar_type scalar_t; 01242 typedef typename mvector_t::local_ordinal_type lno_t; 01243 typedef StridedData<lno_t, scalar_t> input_t; 01244 01245 lno_t numLocalCoords = vectors->getLocalLength(); 01246 01247 // initialize return values 01248 cutDimension = 0; 01249 cutValue = imbalance = weightLeftHalf = weightRightHalf = 0.0; 01250 numPartsLeftHalf = 0; 01251 01253 // Pick a cut direction. 01254 01255 scalar_t globalMinCoord, globalMaxCoord; 01256 ArrayView<lno_t> emptyIndex; 01257 01258 getCutDimension<mvector_t>(env, comm, coordDim, vectors, emptyIndex, 01259 cutDimension, globalMinCoord, globalMaxCoord); 01260 01262 // Compute part sizes for the two parts. 01263 01264 ArrayRCP<double> fractionLeft; 01265 01266 getFractionLeft<Adapter>(env, part0, part1, solution, 01267 fractionLeft, numPartsLeftHalf); 01268 int nVecs = fractionLeft.size(); 01269 01270 // Special case of empty left or empty right. 01271 01272 leftRightFlag lrf; 01273 01274 bool emptyParts = emptyPartsCheck(env, 01275 fractionLeft.view(0, nVecs), // input 01276 globalMinCoord, globalMaxCoord, // input 01277 lrf, cutValue); // output 01278 01279 if (emptyParts){ 01280 01281 for (lno_t i=0; i < lrflags.size(); i++) 01282 lrflags[i] = lrf; 01283 01284 imbalance = 0.0; // perfect balance 01285 scalar_t totalWeight = 0.0; 01286 01287 if (nWeightsPerCoord == 0) 01288 totalWeight = numLocalCoords; 01289 else if (nWeightsPerCoord == 1) { 01290 int wgtidx = coordDim; 01291 const scalar_t *val = vectors->getData(wgtidx).getRawPtr(); 01292 for (lno_t i=0; i < numLocalCoords; i++) 01293 totalWeight += val[i]; 01294 } 01295 else { // need to add up total normed weight 01296 Array<input_t> wgts(nWeightsPerCoord); 01297 int wgtidx = coordDim; 01298 for (int i=0; i < nWeightsPerCoord; i++) 01299 wgts[i] = input_t(vectors->getData(wgtidx++), 1); 01300 01301 part_t numParts, numNonemptyParts; 01302 ArrayRCP<MetricValues<scalar_t> > metrics; 01303 ArrayRCP<scalar_t> weightSums; 01304 01305 globalSumsByPart<scalar_t, unsigned char, lno_t, part_t>( 01306 env, comm, lrflags, nWeightsPerCoord, 01307 wgts.view(0, nWeightsPerCoord), mcnorm, 01308 numParts, numNonemptyParts, metrics, weightSums); 01309 01310 totalWeight = weightSums[1]; // sum normed weight 01311 } 01312 01313 if (lrf == leftFlag){ 01314 numPartsLeftHalf = part1 - part0 + 1; 01315 weightLeftHalf = totalWeight; 01316 weightRightHalf = 0; 01317 } 01318 else{ 01319 numPartsLeftHalf = 0; 01320 weightRightHalf = totalWeight; 01321 weightLeftHalf = 0; 01322 } 01323 01324 env->debug(DETAILED_STATUS, "Exiting determineCut"); 01325 return; 01326 } 01327 01329 // Divide the coordinates into balanced left and right 01330 // halves. 01331 01332 ArrayView<lno_t> emptyIndices; 01333 lno_t localCountLeft; 01334 01335 try{ 01336 BSPfindCut<mvector_t>( env, comm, 01337 params, numTestCuts, tolerance, 01338 cutDimension, coordDim, nWeightsPerCoord, vectors, emptyIndices, 01339 fractionLeft.view(0, nVecs), 01340 globalMinCoord, globalMaxCoord, 01341 cutValue, lrflags.view(0, numLocalCoords), 01342 weightLeftHalf, weightRightHalf, localCountLeft, imbalance); 01343 } 01344 Z2_FORWARD_EXCEPTIONS 01345 env->debug(DETAILED_STATUS, "Exiting determineCut"); 01346 } 01347 01348 01371 template <typename mvector_t, typename Adapter> 01372 void serialRCB( 01373 const RCP<const Environment> &env, 01374 int depth, 01375 const std::bitset<NUM_RCB_PARAMS> ¶ms, 01376 int numTestCuts, 01377 typename mvector_t::scalar_type tolerance, 01378 int coordDim, 01379 int nWeightsPerCoord, 01380 const RCP<mvector_t> &vectors, 01381 ArrayView<typename mvector_t::local_ordinal_type> index, 01382 const RCP<PartitioningSolution<Adapter> > &solution, 01383 typename Adapter::part_t part0, 01384 typename Adapter::part_t part1, 01385 ArrayView<typename Adapter::part_t> partNum) // output 01386 { 01387 env->debug(DETAILED_STATUS, "Entering serialRCB"); 01388 env->timerStart(MICRO_TIMERS, "serialRCB", depth, 2); 01389 01390 typedef typename Adapter::part_t part_t; 01391 typedef typename mvector_t::scalar_type scalar_t; 01392 typedef typename mvector_t::local_ordinal_type lno_t; 01393 01394 RCP<Comm<int> > comm(new Teuchos::SerialComm<int>); 01395 01396 lno_t numLocalCoords=0; 01397 bool useIndices; 01398 bool firstCall=false; 01399 01400 if (index.size() == 0){ 01401 // First time through there are no indices. 01402 useIndices = false; 01403 numLocalCoords = vectors->getLocalLength(); 01404 firstCall = true; 01405 } 01406 else{ 01407 useIndices = true; 01408 numLocalCoords = index.size(); 01409 } 01410 01411 if (env->getDebugLevel() >= DETAILED_STATUS){ 01412 std::ostringstream info; 01413 info << " Number of coordinates: " << numLocalCoords << std::endl; 01414 info << " Use index: " << useIndices << std::endl; 01415 env->debug(DETAILED_STATUS, info.str()); 01416 } 01417 01419 // Are we done? 01420 01421 if (part1 == part0){ 01422 if (useIndices) 01423 for (lno_t i=0; i < numLocalCoords; i++) 01424 partNum[index[i]] = part0; 01425 else 01426 for (lno_t i=0; i < numLocalCoords; i++) 01427 partNum[i] = part0; 01428 01429 env->memory("serial RCB end"); 01430 env->timerStop(MICRO_TIMERS, "serialRCB", depth, 2); 01431 env->debug(DETAILED_STATUS, "Exiting serialRCB"); 01432 01433 return; 01434 } 01435 01437 // Pick a cut direction 01438 01439 int cutDimension; 01440 scalar_t minCoord, maxCoord; 01441 01442 try{ 01443 getCutDimension(env, comm, coordDim, vectors, index, 01444 cutDimension, minCoord, maxCoord); 01445 } 01446 Z2_FORWARD_EXCEPTIONS 01447 01449 // Compute relative sizes of the two halves. 01450 01451 ArrayRCP<double> fractionLeft; 01452 part_t numPartsLeftHalf; 01453 01454 try{ 01455 getFractionLeft<Adapter>(env, part0, part1, solution, 01456 fractionLeft, numPartsLeftHalf); 01457 } 01458 Z2_FORWARD_EXCEPTIONS 01459 int nVecs = fractionLeft.size(); 01460 01461 // Check for special case of empty left or empty right. 01462 01463 scalar_t imbalance, cutValue; //unused for now 01464 leftRightFlag lrf; 01465 01466 bool emptyPart = emptyPartsCheck(env, fractionLeft.view(0, nVecs), 01467 minCoord, maxCoord, lrf, cutValue); 01468 01469 if (emptyPart){ // continue only on the side that is not empty 01470 01471 if (lrf == rightFlag) // right is empty 01472 part1 = part0 + numPartsLeftHalf - 1; 01473 else 01474 part0 = part0 + numPartsLeftHalf; 01475 01476 if (part0 == part1){ 01477 if (useIndices){ 01478 for (lno_t i=0; i < numLocalCoords; i++){ 01479 partNum[index[i]] = part0; 01480 } 01481 } 01482 else{ 01483 for (lno_t i=0; i < numLocalCoords; i++){ 01484 partNum[i] = part0; 01485 } 01486 } 01487 01488 imbalance = 0.0; // perfect 01489 env->timerStop(MICRO_TIMERS, "serialRCB", depth, 2); 01490 env->debug(DETAILED_STATUS, "Exiting serialRCB"); 01491 return; 01492 } 01493 } 01494 01496 // Divide into balanced left and right halves. 01497 01498 scalar_t totalLeft=0, totalRight=0; 01499 lno_t localCountLeft=0, localCountRight=0; 01500 unsigned char *flags = new unsigned char [numLocalCoords]; 01501 env->localMemoryAssertion(__FILE__, __LINE__, numLocalCoords, flags) ; 01502 ArrayRCP<unsigned char> lrflags(flags, 0, numLocalCoords, true); 01503 01504 try{ 01505 BSPfindCut<mvector_t>( env, comm, 01506 params, numTestCuts, tolerance, 01507 cutDimension, coordDim, nWeightsPerCoord, vectors, index, 01508 fractionLeft.view(0, nVecs), 01509 minCoord, maxCoord, 01510 cutValue, lrflags.view(0, numLocalCoords), 01511 totalLeft, totalRight, localCountLeft, imbalance); 01512 } 01513 Z2_FORWARD_EXCEPTIONS 01514 01515 if (firstCall) 01516 env->memory("serial RCB start"); 01517 01519 // Adjust indices for left half and right half 01520 01521 localCountRight = numLocalCoords - localCountLeft; 01522 01523 if (localCountLeft){ 01524 01525 lno_t *newIndex = new lno_t [localCountLeft]; 01526 env->localMemoryAssertion(__FILE__, __LINE__, localCountLeft, newIndex); 01527 ArrayView<lno_t> leftIndices(newIndex, localCountLeft); 01528 01529 if (useIndices){ 01530 for (lno_t i=0, ii=0; i < numLocalCoords; i++) 01531 if (lrflags[i] == leftFlag) 01532 newIndex[ii++] = index[i]; 01533 } 01534 else{ 01535 for (lno_t i=0, ii=0; i < numLocalCoords; i++) 01536 if (lrflags[i] == leftFlag) 01537 newIndex[ii++] = i; 01538 } 01539 01540 part_t newPart1 = part0 + numPartsLeftHalf - 1; 01541 01542 env->timerStop(MICRO_TIMERS, "serialRCB", depth, 2); 01543 01544 serialRCB<mvector_t, Adapter>(env, depth+1, params, numTestCuts, tolerance, 01545 coordDim, nWeightsPerCoord, vectors, leftIndices, 01546 solution, part0, newPart1, partNum); 01547 01548 env->timerStart(MICRO_TIMERS, "serialRCB", depth, 2); 01549 01550 delete [] newIndex; 01551 } 01552 01553 01554 if (localCountRight){ 01555 01556 lno_t *newIndex = new lno_t [localCountRight]; 01557 env->localMemoryAssertion(__FILE__, __LINE__, localCountRight, newIndex); 01558 ArrayView<lno_t> rightIndices(newIndex, localCountRight); 01559 01560 if (useIndices){ 01561 for (lno_t i=0, ii=0; i < numLocalCoords; i++) 01562 if (lrflags[i] == rightFlag){ 01563 newIndex[ii++] = index[i]; 01564 } 01565 } 01566 else{ 01567 for (lno_t i=0, ii=0; i < numLocalCoords; i++) 01568 if (lrflags[i] == rightFlag) 01569 newIndex[ii++] = i; 01570 } 01571 01572 part_t newPart0 = part0 + numPartsLeftHalf; 01573 01574 env->timerStop(MICRO_TIMERS, "serialRCB", depth, 2); 01575 01576 serialRCB<mvector_t, Adapter>(env, depth+1, params, numTestCuts, tolerance, 01577 coordDim, nWeightsPerCoord, vectors, rightIndices, 01578 solution, newPart0, part1, partNum); 01579 01580 env->timerStart(MICRO_TIMERS, "serialRCB", depth, 2); 01581 01582 delete [] newIndex; 01583 } 01584 01585 env->timerStop(MICRO_TIMERS, "serialRCB", depth, 2); 01586 env->debug(DETAILED_STATUS, "Exiting serialRCB"); 01587 } 01588 01589 }// namespace Zoltan2 01590 01591 #endif 01592
1.7.6.1