Zoltan2
Zoltan2_AlgRCB_methods.hpp
Go to the documentation of this file.
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> &params,
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> &params,
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> &params,
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