Zoltan2
Zoltan2_IdentifierTraits.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 // @HEADER
00046 // ***********************************************************************
00047 //            copyright
00048 //
00049 // ***********************************************************************
00050 // @HEADER
00051 
00056 #ifndef _ZOLTAN2_IDENTIFIERTRAITS
00057 #define _ZOLTAN2_IDENTIFIERTRAITS
00058 
00059 #include <Zoltan2_Standards.hpp>
00060 #include <Zoltan2_AlltoAll.hpp>
00061 
00062 #include <Teuchos_SerializationTraits.hpp>
00063 #include <Teuchos_HashUtils.hpp>
00064 #include <Teuchos_ReductionOp.hpp>
00065 
00066 #include <utility>
00067 #include <iostream>
00068 #include <sstream>
00069 #include <string>
00070 #include <limits>
00071 #include <cstdlib>
00072 
00073 using Teuchos::SerializationTraits;
00074 
00075 namespace Zoltan2
00076 {
00077 extern int getHashCode(const unsigned char *a, size_t len);
00078 
00081 template <typename T>
00082   std::pair<T, T> z2LocalMinMax(const T *val, size_t n)
00083 {
00084   T max = std::numeric_limits<T>::min();
00085   T min = std::numeric_limits<T>::max();
00086 
00087   for (size_t i=0; i < n; i++){
00088     if (val[i] < min) min = val[i];
00089     if (val[i] > max) max = val[i];
00090   }
00091   return std::pair<T,T>(min,max);
00092 }
00093 
00094 
00100 template <typename T> class Zoltan2_MinMaxOperation :
00101   public ::Teuchos::ValueTypeReductionOp<int, char>
00102 {
00103 public:
00104   void reduce(
00105     const int count, const char inBuffer[], char inoutBuffer[]) const
00106   {
00107     const T *in = reinterpret_cast<const T*>(inBuffer);
00108     T *inout = reinterpret_cast<T*>(inoutBuffer);
00109 
00110     if (in[0] < inout[0]) inout[0] = in[0];
00111     if (in[1] > inout[1]) inout[1] = in[1];
00112   }
00113 };
00114 
00117 template <typename T>
00118   void z2GlobalMinMax(const Comm<int> &comm, bool noLocalValues,
00119     T localMin, T localMax, T &globalMin, T &globalMax)
00120 {
00121   if (noLocalValues){
00122     localMin = std::numeric_limits<T>::max();
00123     localMax = std::numeric_limits<T>::min();
00124   }
00125 
00126   if (comm.getSize() == 1){
00127     globalMin = localMin;
00128     globalMax = localMax;
00129     return;
00130   }
00131 
00132   T localValues[2] = {localMin, localMax};
00133   T globalValues[2];
00134 
00135   char *lv = reinterpret_cast<char *>(&localValues[0]);
00136   char *gv = reinterpret_cast<char *>(&globalValues[0]);
00137 
00138   Zoltan2_MinMaxOperation<T> reductionOp;
00139   ::Teuchos::reduceAll<int, char>(comm, reductionOp, 2*sizeof(T), lv, gv);
00140 
00141   globalMin = globalValues[0];
00142   globalMax = globalValues[1];
00143 }
00144 
00147 template <typename T>
00148   bool z2AreConsecutive(const T *val, size_t n)
00149 {
00150   if (n == 0) return true;
00151 
00152   if (val[n-1] - val[0] + 1 != T(n))
00153     return false;
00154 
00155   T nextval = val[0]+1;
00156   for (size_t i=1; i < n; i++){
00157     if (val[i] != nextval)
00158       return false;
00159     nextval++;
00160   }
00161   return true;
00162 }
00163 
00166 template <typename T>
00167   std::string stringifyOrdinal(T ordinal)
00168 {
00169   std::ostringstream oss;
00170   oss << ordinal;
00171   return oss.str();
00172 }
00173 
00176 template<typename T>
00177 struct UndefIdTraits
00178 {
00179 static inline void noop() {
00180   T::UsingInvalidGlobalIdentifierDataType();
00181 }
00182 static inline T invalid() {
00183   return T::UsingInvalidGlobalIdentifierDataType();
00184 }
00185 };
00186 
00187 
00239 template<typename T>
00240 struct IdentifierTraits {
00241 
00247   static int hashCode(const T id) {
00248    return UndefIdTraits<int>::invalid();
00249   }
00250 
00255   static inline bool hasUniqueKey(){
00256    return UndefIdTraits<bool>::invalid();}
00257 
00265   static inline double key(const T c){return static_cast<double>(c); }
00266 
00271   static inline std::string name() {
00272     return UndefIdTraits<std::string>::invalid();
00273   }
00274 
00280   static std::string stringify(T val) {
00281     return UndefIdTraits<std::string>::invalid();
00282   }
00283 
00290   static inline bool isGlobalOrdinal() {
00291     return UndefIdTraits<bool>::invalid();
00292   }
00293 
00303   static inline T difference(const T a, const T b) {
00304     return UndefIdTraits<bool>::invalid();
00305   }
00306 
00312   static inline bool is_valid_id_type() { return false; }
00313 
00323   static void minMax(const T *values, size_t numValues, T &min, T&max) {
00324     UndefIdTraits<T>::noop();
00325   }
00326 
00340   static void globalMinMax(const Comm<int> &comm, bool flag,
00341       T localMin, T localMax, T &globalMin, T &globalMax){
00342     UndefIdTraits<T>::noop();
00343   }
00344 
00355   static bool areConsecutive(const T *val, size_t n){
00356     return UndefIdTraits<bool>::invalid();
00357   }
00358 
00359 };
00360 
00361 #ifndef DOXYGEN_SHOULD_SKIP_THIS
00362 
00363 /* The specializations of the hashCode is not a true hash.
00364  * For types that can fit in an int it is just a typecast to int. 
00365  * This can be used with a modulo capacity of table/array to find the basic
00366  * hash. For types larger than that can fit in an int, it tries to be a
00367  * little smarter by adding all the bytes into an int. It also ensures it is
00368  * positive so you can use it as an index.
00369  * */
00370 
00371 template<>
00372 struct IdentifierTraits<char> {
00373   typedef char T;
00374   static inline int hashCode(const T c) {return static_cast<int>(c);}
00375   static inline bool hasUniqueKey() { return true;}
00376   static inline double key(const T c){return static_cast<double>(c); }
00377   static inline std::string name()     {return("char");}
00378   static std::string stringify(T val) {return stringifyOrdinal(val);}
00379   static inline bool isGlobalOrdinal() {return true; }
00380 
00381   static inline T difference(const T a, const T b) { return (b-a); }
00382   static inline bool is_valid_id_type() {return true; }
00383   static void minMax(const T *values, size_t n, T &min, T &max) {
00384     std::pair<T, T> ext = z2LocalMinMax(values, n);
00385     min = ext.first;
00386     max = ext.second;
00387   }
00388   static void globalMinMax(const Comm<int> &comm, bool flag,
00389       T localMin, T localMax, T &globalMin, T &globalMax){
00390     z2GlobalMinMax(comm, flag, localMin, localMax, globalMin, globalMax);}
00391   static bool areConsecutive(const T *val, size_t n){
00392    return z2AreConsecutive(val, n); }
00393 };
00394 
00395 template<>
00396 struct IdentifierTraits<unsigned char> {
00397   typedef unsigned char T;
00398   static inline int hashCode(const T c) {return static_cast<int>(c);}
00399   static inline bool hasUniqueKey() { return true;}
00400   static inline double key(const T c){return static_cast<double>(c); }
00401   static inline std::string name()     {return("unsigned char");}
00402   static std::string stringify(T val) {return stringifyOrdinal(val);}
00403   static inline bool isGlobalOrdinal() {return true; }
00404 
00405   static inline T difference(const T a, const T b) { return (b-a); }
00406   static inline bool is_valid_id_type() {return true; }
00407   static void minMax(const T *values, size_t n, T &min, T &max) {
00408     std::pair<T, T> ext = z2LocalMinMax(values, n);
00409     min = ext.first;
00410     max = ext.second;
00411   }
00412   static void globalMinMax(const Comm<int> &comm, bool flag,
00413       T localMin, T localMax, T &globalMin, T &globalMax){
00414     z2GlobalMinMax(comm, flag, localMin, localMax, globalMin, globalMax);}
00415   static bool areConsecutive(const T *val, size_t n){
00416    return z2AreConsecutive(val, n); }
00417 };
00418 
00419 template<>
00420 struct IdentifierTraits<short> {
00421   typedef short T;
00422   static inline int hashCode(const T  a) {return static_cast<int>(a);}
00423   static inline bool hasUniqueKey() { return true;}
00424   static inline double key(const T a){return static_cast<double>(a); }
00425   static inline std::string name()   {return("short");}
00426   static std::string stringify(T val) {return stringifyOrdinal(val);}
00427   static inline bool isGlobalOrdinal() {return true; }
00428 
00429   static inline T difference(const T a, const T b) { return (b-a); }
00430   static inline bool is_valid_id_type() {return true; }
00431   static void minMax(const T *values, size_t n, T &min, T &max) {
00432     std::pair<T, T> ext = z2LocalMinMax(values, n);
00433     min = ext.first;
00434     max = ext.second;
00435   }
00436   static void globalMinMax(const Comm<int> &comm, bool flag,
00437       T localMin, T localMax, T &globalMin, T &globalMax){
00438     z2GlobalMinMax(comm, flag, localMin, localMax, globalMin, globalMax);}
00439   static bool areConsecutive(const T *val, size_t n){
00440   return z2AreConsecutive(val, n); }
00441 };
00442 
00443 template<>
00444 struct IdentifierTraits<unsigned short> {
00445   typedef unsigned short T;
00446   static inline int hashCode(const T  a) {return static_cast<int>(a);}
00447   static inline bool hasUniqueKey() { return true;}
00448   static inline double key(const T a){return static_cast<double>(a); }
00449   static inline std::string name()   {return("unsigned short");}
00450   static std::string stringify(T val) {return stringifyOrdinal(val);}
00451   static inline bool isGlobalOrdinal() {return true; }
00452 
00453   static inline T difference(const T a, const T b) { return (b-a); }
00454   static inline bool is_valid_id_type() {return true; }
00455   static void minMax(const T *values, size_t n, T &min, T &max) {
00456     std::pair<T, T> ext = z2LocalMinMax(values, n);
00457     min = ext.first;
00458     max = ext.second;
00459   }
00460   static void globalMinMax(const Comm<int> &comm, bool flag,
00461       T localMin, T localMax, T &globalMin, T &globalMax){
00462     z2GlobalMinMax(comm, flag, localMin, localMax, globalMin, globalMax);}
00463   static bool areConsecutive(const T *val, size_t n){
00464   return z2AreConsecutive(val, n); }
00465 };
00466 
00467 template<>
00468 struct IdentifierTraits<int> {
00469   typedef int T;
00470   static inline int hashCode(const T  a) {return static_cast<int>(a);}
00471   static inline bool hasUniqueKey() { return true;}
00472   static inline double key(const T a){return static_cast<double>(a); }
00473   static inline std::string name()   {return("int");}
00474   static std::string stringify(T val) {return stringifyOrdinal(val);}
00475   static inline bool isGlobalOrdinal() {return true; }
00476 
00477   static inline T difference(const T a, const T b) { return (b-a); }
00478   static inline bool is_valid_id_type() {return true; }
00479   static void minMax(const T *values, size_t n, T &min, T &max) {
00480     std::pair<T, T> ext = z2LocalMinMax(values, n);
00481     min = ext.first;
00482     max = ext.second;
00483   }
00484   static void globalMinMax(const Comm<int> &comm, bool flag,
00485       T localMin, T localMax, T &globalMin, T &globalMax){
00486     z2GlobalMinMax(comm, flag, localMin, localMax, globalMin, globalMax);}
00487   static bool areConsecutive(const T *val, size_t n){
00488   return z2AreConsecutive(val, n); }
00489 };
00490 
00491 template<>
00492 struct IdentifierTraits<unsigned int> {
00493   typedef unsigned int T;
00494   static inline int hashCode(const T  a) {
00495     return getHashCode(
00496       reinterpret_cast<const unsigned char *>(&a), sizeof(T));}
00497   static inline bool hasUniqueKey() { return true;}
00498   static inline double key(const T a){return static_cast<double>(a); }
00499   static inline std::string name()   {return("unsigned int");}
00500   static std::string stringify(T val) {return stringifyOrdinal(val);}
00501   static inline bool isGlobalOrdinal() {return true; }
00502 
00503   static inline T difference(const T a, const T b) { return (b-a); }
00504   static inline bool is_valid_id_type() {return true; }
00505   static void minMax(const T *values, size_t n, T &min, T &max) {
00506     std::pair<T, T> ext = z2LocalMinMax(values, n);
00507     min = ext.first;
00508     max = ext.second;
00509   }
00510   static void globalMinMax(const Comm<int> &comm, bool flag,
00511       T localMin, T localMax, T &globalMin, T &globalMax){
00512     z2GlobalMinMax(comm, flag, localMin, localMax, globalMin, globalMax);}
00513   static bool areConsecutive(const T *val, size_t n){
00514   return z2AreConsecutive(val, n); }
00515 };
00516 
00517 
00518 template<>
00519 struct IdentifierTraits<long> {
00520   typedef long T;
00521   static inline int hashCode(const T a) {
00522     return getHashCode(
00523       reinterpret_cast<const unsigned char *>(&a), sizeof(T));}
00524   static inline bool hasUniqueKey() { return true;}
00525   static inline double key(const T a){return static_cast<double>(a); }
00526   static inline std::string name()    {return("long");}
00527   static std::string stringify(T val) {return stringifyOrdinal(val);}
00528   static inline bool isGlobalOrdinal() {return true; }
00529   static inline T difference(const T a, const T b) { return (b-a); }
00530   static inline bool is_valid_id_type() {return true; }
00531   static void minMax(const T *values, size_t n, T &min, T &max) {
00532     std::pair<T, T> ext = z2LocalMinMax(values, n);
00533     min = ext.first;
00534     max = ext.second;
00535   }
00536   static void globalMinMax(const Comm<int> &comm, bool flag,
00537       T localMin, T localMax, T &globalMin, T &globalMax){
00538     z2GlobalMinMax(comm, flag, localMin, localMax, globalMin, globalMax);}
00539   static bool areConsecutive(const T *val, size_t n){
00540     return z2AreConsecutive(val, n); }
00541 };
00542 
00543 template<>
00544 struct IdentifierTraits<unsigned long> {
00545   typedef unsigned long T;
00546   static inline int hashCode(const T a) {
00547     return getHashCode(
00548       reinterpret_cast<const unsigned char *>(&a), sizeof(T));}
00549   static inline bool hasUniqueKey() { return true;}
00550   static inline double key(const T a){return static_cast<double>(a);}
00551   static inline std::string name()   {return("unsigned long");}
00552   static std::string stringify(T val) {return stringifyOrdinal(val);}
00553   static inline bool isGlobalOrdinal() {return true; }
00554   static inline T difference(const T a, const T b) { return (b-a); }
00555   static inline bool is_valid_id_type() {return true; }
00556   static void minMax(const T *values, size_t n, T &min, T &max) {
00557     std::pair<T, T> ext = z2LocalMinMax(values, n);
00558     min = ext.first;
00559     max = ext.second;
00560   }
00561   static void globalMinMax(const Comm<int> &comm, bool flag,
00562       T localMin, T localMax, T &globalMin, T &globalMax){
00563     z2GlobalMinMax(comm, flag, localMin, localMax, globalMin, globalMax);}
00564   static bool areConsecutive(const T *val, size_t n){
00565     return z2AreConsecutive(val, n); }
00566 };
00567 
00568 #ifdef HAVE_ZOLTAN2_LONG_LONG
00569 
00570 template<>
00571 struct IdentifierTraits<long long> {
00572   typedef long long T;
00573   static inline int hashCode(const T a) {
00574     return getHashCode(
00575       reinterpret_cast<const unsigned char *>(&a), sizeof(T));}
00576   static inline bool hasUniqueKey() { return true;}
00577   static inline double key(const T a){return static_cast<double>(a); }
00578   static inline std::string name()    {return("long long");}
00579   static std::string stringify(T val) {return stringifyOrdinal(val);}
00580   static inline bool isGlobalOrdinal() {return true; }
00581   static inline T difference(const T a, const T b) { return (b-a); }
00582   static inline bool is_valid_id_type() {return true; }
00583   static void minMax(const T *values, size_t n, T &min, T &max) {
00584     std::pair<T, T> ext = z2LocalMinMax(values, n);
00585     min = ext.first;
00586     max = ext.second;
00587   }
00588   static void globalMinMax(const Comm<int> &comm, bool flag,
00589       T localMin, T localMax, T &globalMin, T &globalMax){
00590     z2GlobalMinMax(comm, flag, localMin, localMax, globalMin, globalMax);}
00591   static bool areConsecutive(const T *val, size_t n){
00592     return z2AreConsecutive(val, n); }
00593 };
00594 
00595 template<>
00596 struct IdentifierTraits<unsigned long long> {
00597   typedef unsigned long long T;
00598   static inline int hashCode(const T a) {
00599     return getHashCode(
00600       reinterpret_cast<const unsigned char *>(&a), sizeof(T));}
00601   static inline bool hasUniqueKey() { return true;}
00602   static inline double key(const T a){return static_cast<double>(a);}
00603   static inline std::string name()   {return("unsigned long long");}
00604   static std::string stringify(T val) {return stringifyOrdinal(val);}
00605   static inline bool isGlobalOrdinal() {return true; }
00606   static inline T difference(const T a, const T b) { return (b-a); }
00607   static inline bool is_valid_id_type() {return true; }
00608   static void minMax(const T *values, size_t n, T &min, T &max) {
00609     std::pair<T, T> ext = z2LocalMinMax(values, n);
00610     min = ext.first;
00611     max = ext.second;
00612   }
00613   static void globalMinMax(const Comm<int> &comm, bool flag,
00614       T localMin, T localMax, T &globalMin, T &globalMax){
00615     z2GlobalMinMax(comm, flag, localMin, localMax, globalMin, globalMax);}
00616   static bool areConsecutive(const T *val, size_t n){
00617     return z2AreConsecutive(val, n); }
00618 };
00619 
00620 #endif
00621 
00622 template<>
00623 struct IdentifierTraits<std::string> {
00624   typedef std::string T;
00625   static inline int hashCode(const T a) {
00626     return getHashCode(
00627       reinterpret_cast<const unsigned char *>(a.c_str()), a.size());}
00628   static inline bool hasUniqueKey() { return false;}
00629   static inline double key(const T a){ throw std::logic_error("invalid call");}
00630   static inline std::string name()   {return("string");}
00631   static std::string stringify(T val) {return val;}
00632   static inline bool isGlobalOrdinal() {return false; }
00633   static inline T difference(const T a, const T b) {
00634     throw std::logic_error("invalid call");}
00635   static inline bool is_valid_id_type() {return true; }
00636   static void minMax(const T *values, size_t n, T &min, T &max) {
00637     throw std::logic_error("invalid call");}
00638   static void globalMinMax(const Comm<int> &comm, bool flag,
00639       T localMin, T localMax, T &globalMin, T &globalMax){
00640     throw std::logic_error("invalid call");}
00641   static bool areConsecutive(const T *val, size_t n){
00642     throw std::logic_error("invalid call");}
00643 };
00644 
00645 template<typename T1, typename T2>
00646 struct IdentifierTraits<std::pair<T1, T2> > {
00647   typedef std::pair<T1, T2> pair_t;
00648   typedef typename std::pair<pair_t, pair_t> pairPair_t;
00649 
00650   static inline int hashCode(const pair_t p)  {
00651     int total = IdentifierTraits<T1>::hashCode(p.first) +
00652                 IdentifierTraits<T2>::hashCode(p.second);
00653     if (total < 0)
00654     {
00655         /* Convert the largest -ve int to zero and -1 to
00656          * std::numeric_limits<int>::max()
00657          * */
00658         size_t maxIntBeforeWrap = std::numeric_limits<int>::max();
00659         maxIntBeforeWrap ++;
00660         total += maxIntBeforeWrap;
00661     }
00662     return total;
00663   }
00664 
00665   static inline bool hasUniqueKey() {
00666     if ((sizeof(T1)*2 <= sizeof(double))&&(sizeof(T2)*2 <= sizeof(double)))
00667       return true;
00668     else
00669       return false;
00670   }
00671 
00672   static inline double key(const pair_t p)  {
00673     size_t nbytes = sizeof(double) / 2;
00674     if ((sizeof(T1) > nbytes)||(sizeof(T2) > nbytes))
00675       throw std::logic_error("invalid call");
00676     else{
00677       double keyVal=0;
00678       char *cx = reinterpret_cast<char *>(&keyVal);
00679       char *cy = cx + nbytes;
00680       T1 *xpos = reinterpret_cast<T1 *>(cx + nbytes-sizeof(T1));
00681       T2 *ypos = reinterpret_cast<T2 *>(cy + nbytes-sizeof(T2));
00682       // mfh 17 Apr 2014: Must do a memcpy here rather than an
00683       // assignment, in order to avoid breaking strict ANSI aliasing
00684       // rules (which compilers expect in order to optimize
00685       // correctly).
00686       memcpy (xpos, &(p.first), sizeof (T1)); // *xpos = p.first;
00687       memcpy (ypos, &(p.second), sizeof (T2)); // *ypos = p.second;
00688       return keyVal;
00689     }
00690   }
00691 
00692   static inline std::string name() {
00693      std::string s("std::pair<");
00694      s += IdentifierTraits<T1>::name();
00695      s += std::string(", ");
00696      s += IdentifierTraits<T2>::name();
00697      s += std::string(">");
00698      return s;
00699   }
00700 
00701   static std::string stringify(pair_t val) {
00702     std::ostringstream oss;
00703     oss << "pair<" << IdentifierTraits<T1>::name();
00704     oss << "," << IdentifierTraits<T2>::name();
00705     oss << ">(" << val.first << "," << val.second << ")";
00706     return oss.str();
00707   }
00708 
00709   static inline bool isGlobalOrdinal() {return false; }
00710 
00711   static inline pair_t difference( const pair_t a, const pair_t b) {
00712       throw std::logic_error("invalid call");
00713       return pair_t();}
00714 
00715   static inline bool is_valid_id_type() {
00716     return (sizeof(T1)+sizeof(T2) <= sizeof(double)); }
00717 
00718   static void minMax(const pair_t *values, size_t n, pair_t &min, pair_t &max) {
00719       throw std::logic_error("invalid call");}
00720 
00721   static void globalMinMax(const Comm<int> &comm, bool flag,
00722       pair_t localMin, pair_t localMax,
00723       pair_t &globalMin, pair_t &globalMax){
00724       throw std::logic_error("invalid call");}
00725 
00726   static bool areConsecutive(const pair_t *val, size_t n){
00727       throw std::logic_error("invalid call");
00728       return false; }
00729 };
00730 
00732 //  A helper function.  If T is an ordinal, are the values
00733 //    globally consecutive?  If so return true, otherwise
00734 //    return false.
00735 //
00736 //  On return, globalLen is set to the sum of the local lengths.
00737 //
00738 //  If T is an ordinal, but the list is not globally consecutive,
00739 //    on return dist[0] is set to the global minimum of
00740 //    the values and dist[1] to the global maximum.
00741 //
00742 //  If T is an ordinal and the list is globally consecutive,
00743 //    on return dist[p] is set to val[0] on process p.  dist[nprocs]
00744 //    is set to one past the global maximum value.
00746 
00747 template <typename T>
00748   bool globallyConsecutiveOrdinals(
00749     const Comm<int> &comm, const Environment &env,
00750     const T* val, size_t len,
00751     ArrayRCP<T> &dist, size_t &globalLen)
00752 {
00753   // Non-ordinals can not be consecutive.
00754 
00755   if (!IdentifierTraits<T>::isGlobalOrdinal())
00756     return false;
00757 
00758   // return values
00759 
00760   T *distBuf= NULL;
00761   T *minMaxBuf= NULL;
00762   globalLen = 0;
00763 
00764   // Locally consecutive?
00765 
00766   int nprocs = comm.getSize();
00767   bool locallyConsecutive = IdentifierTraits<T>::areConsecutive(val, len);
00768   bool globallyConsecutive = false;
00769 
00770   if (nprocs == 1){
00771     if (locallyConsecutive){
00772       distBuf = new T [2];
00773       if (len > 0){
00774         distBuf[0] = val[0];
00775         distBuf[1] = val[len-1] + 1;
00776       }
00777       else{
00778         distBuf[0] = 0;
00779         distBuf[1] = 0;
00780       }
00781     }
00782     else{
00783       std::pair<T, T> extrema = z2LocalMinMax(val, len);
00784       minMaxBuf = new T [2];
00785       minMaxBuf[0] = extrema.first;
00786       minMaxBuf[1] = extrema.second;
00787     }
00788 
00789     globalLen = len;
00790     globallyConsecutive = locallyConsecutive;
00791   }
00792   else{   // nprocs > 1
00793     try{
00794       reduceAll<int, size_t>(comm, ::Teuchos::REDUCE_SUM, 1, &len, &globalLen);
00795     }
00796     Z2_THROW_OUTSIDE_ERROR(env);
00797 
00798     T v0, v1, gMin, gMax;
00799 
00800     if (len > 0){
00801       v0 = val[0];
00802       v1 = val[len-1];
00803     }
00804     else {
00805       v0 = std::numeric_limits<T>::max();
00806       v1 = std::numeric_limits<T>::min();
00807     }
00808 
00809     try{
00810       IdentifierTraits<T>::globalMinMax(comm, len==0, v0, v1, gMin, gMax);
00811     }
00812     Z2_FORWARD_EXCEPTIONS;
00813 
00814     int lFlag = (locallyConsecutive ? 1 : 0);
00815     int gFlag = 0;
00816 
00817     try{
00818       reduceAll<int, int>(comm, ::Teuchos::REDUCE_MIN, 1, &lFlag, &gFlag);
00819     }
00820     Z2_THROW_OUTSIDE_ERROR(env);
00821 
00822     if (gFlag == 1){  // all processes have consecutive values
00823 
00824       size_t g0 = static_cast<size_t>(gMin);
00825       size_t g1 = static_cast<size_t>(gMax);
00826 
00827       if (g1 - g0 + 1 == globalLen){
00828         size_t sentinel = g1 + 1;   // invalid id
00829         size_t sendVal = sentinel;
00830         if (len > 0)
00831           sendVal = static_cast<size_t>(v0);
00832 
00833         size_t *recvBuf = new size_t[nprocs];
00834 
00835         try {
00836           ::Teuchos::gatherAll<int, size_t>(comm, 1, &sendVal, nprocs, recvBuf);
00837         }
00838         Z2_THROW_OUTSIDE_ERROR(env);
00839 
00840         int numNoIds = 0;  // number of procs with no ids
00841         for (int i=0; i < nprocs; i++)
00842           if (recvBuf[i] == sentinel)
00843             numNoIds++;
00844 
00845         globallyConsecutive = true;
00846 
00847         if (numNoIds == 0){
00848           for (int i=1; globallyConsecutive && i < nprocs; i++)
00849             if (recvBuf[i] < recvBuf[i-1])
00850               globallyConsecutive = false;
00851 
00852           if (globallyConsecutive){
00853             distBuf = new T [nprocs+1];
00854             for (int i=0; i < nprocs; i++)
00855               distBuf[i] = static_cast<T>(recvBuf[i]);
00856             distBuf[nprocs] = static_cast<T>(sentinel);
00857           }
00858         }
00859         else{
00860           Array<int> index;
00861           for (int i=0; i < nprocs; i++)
00862             if (recvBuf[i] != sentinel)
00863               index.push_back(i);
00864 
00865           for (int i=1; i < index.size(); i++){
00866             if (recvBuf[index[i]] < recvBuf[index[i-1]])
00867               globallyConsecutive = false;
00868           }
00869 
00870           if (globallyConsecutive){
00871             distBuf = new T [nprocs+1];
00872             for (int i=0; i < nprocs+1; i++)
00873               distBuf[i] = static_cast<T>(sentinel);
00874 
00875             for (int i=0; i < index.size(); i++)
00876               distBuf[index[i]] = static_cast<T>(recvBuf[index[i]]);
00877 
00878             T useValue = static_cast<T>(sentinel);
00879             for (int i = nprocs-1; i >= 0; i--){
00880               if (distBuf[i] == static_cast<T>(sentinel))
00881                 distBuf[i] = useValue;
00882               else
00883                 useValue = distBuf[i];
00884             }
00885           }
00886         }
00887         delete [] recvBuf;
00888       }
00889     }  // all processes have locally consecutive values
00890 
00891     if (!globallyConsecutive){
00892       minMaxBuf = new T [2];
00893       minMaxBuf[0] = gMin;
00894       minMaxBuf[1] = gMax;
00895     }
00896   }    // nprocs > 1
00897 
00898   if (minMaxBuf)
00899     dist = arcp(minMaxBuf, 0, 2, true);
00900   else if (distBuf)
00901     dist = arcp(distBuf, 0, nprocs+1, true);
00902   else
00903      throw std::logic_error("no buffer");  // should never get here
00904 
00905   return globallyConsecutive;
00906 }
00907 
00908 #endif  // DOXYGEN_SHOULD_SKIP_THIS
00909 
00910 } // namespace Z2
00911 
00912 #endif // _ZOLTAN2_IDENTIFIERTRAITS