|
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_INTEGERRANGELIST_HPP_ 00051 #define _ZOLTAN2_INTEGERRANGELIST_HPP_ 00052 00053 #include <Zoltan2_config.h> 00054 00055 #include <Teuchos_ParameterEntryValidator.hpp> 00056 #include <Teuchos_ValidatorXMLConverter.hpp> 00057 #include <Teuchos_XMLObject.hpp> 00058 #include <Teuchos_ValidatorMaps.hpp> 00059 #include <Teuchos_DummyObjectGetter.hpp> 00060 #include <Teuchos_StrUtils.hpp> 00061 00062 #ifdef _MSC_VER 00063 // for isspace(int), else one gets isspace(_Elem _Ch, const locale& _Loc) from <locale> 00064 #include <cctype> 00065 #endif 00066 00067 // Had to redefine this type from Teuchos_ParameterEntryValidator.hpp. 00068 // Compiler stumbled on it. 00069 typedef Teuchos::RCP<const Teuchos::Array<std::string> > ValidStringsList; 00070 00071 namespace Zoltan2{ 00072 00076 enum RangeType { 00077 RANGE_INCLUDES_ALL, 00078 RANGE_IS_EMPTY, 00079 RANGE_IS_LISTED, 00080 NUM_RANGE_TYPES 00081 }; 00082 00083 template <typename T> class IntegerRangeListValidator; 00084 00086 // Helper functions for interpreting integer range list arrays. 00088 00095 template <typename Integral> 00096 bool validIntegralRangeList(const Teuchos::Array<Integral> &vals) 00097 { 00098 typedef typename Teuchos::Array<Integral>::size_type arraySize_t; 00099 arraySize_t len = vals.size(); 00100 if (len==0) 00101 return false; 00102 00103 Integral flag = vals[len-1]; 00104 if ((flag != RANGE_INCLUDES_ALL) && (flag != RANGE_IS_EMPTY) && 00105 (flag != RANGE_IS_LISTED)) 00106 return false; 00107 00108 return true; 00109 } 00110 00125 template <typename Integral> 00126 bool allValuesAreInRangeList(const Teuchos::Array<Integral> &vals) 00127 { 00128 if (!validIntegralRangeList(vals)) 00129 throw std::runtime_error("list is not a valid range list"); 00130 return vals[vals.size()-1] == RANGE_INCLUDES_ALL; 00131 } 00132 00147 template <typename Integral> 00148 bool allValuesAreInRangeList(const Teuchos::ParameterEntry &e) 00149 { 00150 if (!e.isType<Teuchos::Array<Integral> >()) 00151 throw std::runtime_error("Should not call until modified"); 00152 00153 Teuchos::Array<Integral> *valPtr=NULL; 00154 Teuchos::Array<Integral> &vals = e.getValue(valPtr); 00155 return allValuesAreInRangeList(vals); 00156 } 00157 00172 template <typename Integral> 00173 bool noValuesAreInRangeList(const Teuchos::Array<Integral> &vals) 00174 { 00175 if (!validIntegralRangeList(vals)) 00176 throw std::runtime_error("list is not a valid range list"); 00177 return vals[vals.size()-1] == RANGE_IS_EMPTY; 00178 } 00179 00194 template <typename Integral> 00195 bool noValuesAreInRangeList(const Teuchos::ParameterEntry &e) 00196 { 00197 if (!e.isType<Teuchos::Array<Integral> >()) 00198 throw std::runtime_error("Should not call until modified"); 00199 00200 Teuchos::Array<Integral> *valPtr=NULL; 00201 Teuchos::Array<Integral> &vals = e.getValue(valPtr); 00202 return noValuesAreInRangeList(vals); 00203 } 00204 00205 // TODO : 00206 // inList(std::vector<Integral> &val, std::vector<bool> &result) 00207 00219 template <typename Integral> 00220 bool IsInRangeList(const Integral val, const Teuchos::Array<Integral> &valList, bool sorted=true) 00221 { 00222 if (allValuesAreInRangeList(valList)) 00223 return true; 00224 else if (noValuesAreInRangeList(valList)) 00225 return false; 00226 00227 if (sorted){ 00228 typename Teuchos::Array<Integral>::const_iterator flag = valList.end(); 00229 --flag; 00230 if (std::binary_search(valList.begin(), flag, val)) 00231 return true; 00232 else 00233 return false; 00234 } 00235 else{ 00236 for (typename Teuchos::Array<Integral>::size_type i=0; i < valList.size()-1; i++){ 00237 if (valList[i] == val) 00238 return true; 00239 } 00240 return false; 00241 } 00242 } 00243 00254 template <typename Integral> 00255 bool IsInRangeList(const Integral val, const Teuchos::ParameterEntry &e) 00256 { 00257 if (!e.isType<Teuchos::Array<Integral> >()) 00258 throw std::runtime_error("Should not call until modified"); 00259 00260 Teuchos::Array<Integral> *valPtr=NULL; 00261 Teuchos::Array<Integral> &valList = e.getValue(valPtr); 00262 00263 typedef IntegerRangeListValidator<Integral> irl_t; 00264 RCP<const irl_t> irl; 00265 bool fail = false; 00266 00267 RCP<const Teuchos::ParameterEntryValidator> valtor = e.validator(); 00268 if (!valtor.is_null()){ 00269 try{ 00270 irl = rcp_dynamic_cast<const irl_t>(valtor); 00271 } 00272 catch (...){ 00273 fail = true; 00274 } 00275 } 00276 else{ 00277 fail = true; 00278 } 00279 00280 if (fail) 00281 throw std::runtime_error("wrong type of parameter entry"); 00282 00283 bool sorted = irl->inputListWillBeSorted(); 00284 00285 return IsInRangeList(val, valList, sorted); 00286 } 00287 00296 template <typename Integral> 00297 Teuchos::ArrayView<Integral> getList(Teuchos::Array<Integral> &irl) 00298 { 00299 Teuchos::ArrayView<Integral> av; // av.size() == 0 00300 00301 if (!Zoltan2::allValuesAreInRangeList(irl) && 00302 !Zoltan2::noValuesAreInRangeList(irl)) 00303 av = irl.view(0, irl.size()-1); // skip last value, it's a flag 00304 00305 return av; 00306 } 00307 00316 template <typename Integral> 00317 void printIntegralRangeList(std::ostream &os, Teuchos::Array<Integral> &irl) 00318 { 00319 if (Zoltan2::allValuesAreInRangeList(irl)) 00320 os << "all"; 00321 else if (Zoltan2::noValuesAreInRangeList(irl)) 00322 os << "empty"; 00323 else{ 00324 Teuchos::ArrayView<const Integral> view = 00325 irl.view(0, irl.size()-1); // skip last value, it's a flag 00326 os << view; 00327 } 00328 } 00329 00331 // Validator class 00333 00393 template <typename Integral> 00394 class IntegerRangeListValidator : public Teuchos::ParameterEntryValidator 00395 { 00396 private: 00397 00398 #ifndef DOXYGEN_SHOULD_SKIP_THIS 00399 00400 Integral min_; 00401 Integral max_; 00402 bool unsorted_; 00403 00404 static const std::string listDelim_; 00405 static const std::string rangeDelim_; 00406 static const std::string allText_; 00407 00408 static void checkValid(char c); 00409 static bool listSaysAll(std::string &l); 00410 static int breakRange(std::string &range, std::string &from, std::string &to); 00411 00412 #endif 00413 00414 public: 00420 IntegerRangeListValidator(bool unsorted=false); 00421 00431 IntegerRangeListValidator(Integral validMin, Integral validMax, 00432 bool unsorted=false); 00433 00434 // Implementation of ParameterEntryValidator interface 00435 00436 const std::string getXMLTypeName() const; 00437 00438 void printDoc(std::string const& docString, std::ostream &out) const; 00439 00440 ValidStringsList validStringValues() const ; 00441 00442 void validate( Teuchos::ParameterEntry const& entry, 00443 std::string const& paramName, std::string const& sublistName 00444 ) const; 00445 00446 void validateAndModify( std::string const& paramName, 00447 std::string const& sublistName, Teuchos::ParameterEntry * entry 00448 ) const; 00449 00450 // IntegerRangeListValidator methods 00451 00457 Integral getAllowedMinimum() const { return min_;} 00458 00464 Integral getAllowedMaximum() const { return max_;} 00465 00472 bool inputListWillBeSorted() const { return !unsorted_;} 00473 00474 }; // end class 00475 00477 // Class definitions 00479 00480 template <typename Integral> 00481 const std::string IntegerRangeListValidator<Integral>::listDelim_(","); 00482 00483 template <typename Integral> 00484 const std::string IntegerRangeListValidator<Integral>::rangeDelim_("-"); 00485 00486 template <typename Integral> 00487 const std::string IntegerRangeListValidator<Integral>::allText_("all"); 00488 00489 template <typename Integral> 00490 void IntegerRangeListValidator<Integral>::checkValid(char c) 00491 { 00492 if (std::isspace(c) || std::isdigit(c) || (c == ',') || (c == '-')) 00493 return; 00494 else 00495 throw std::runtime_error("invalid integer range list"); 00496 } 00497 00498 template <typename Integral> 00499 bool IntegerRangeListValidator<Integral>::listSaysAll(std::string &l) 00500 { 00501 std::transform(l.begin(), l.end(), l.begin(), (int(*)(int)) tolower); 00502 if (l.find(allText_) != std::string::npos) 00503 return true; // "all" is in the string 00504 else 00505 return false; 00506 } 00507 00508 template <typename Integral> 00509 int IntegerRangeListValidator<Integral>::breakRange( 00510 std::string &range, std::string &from, std::string &to) 00511 { 00512 from.clear(); 00513 to.clear(); 00514 std::string::size_type loc = range.find(rangeDelim_); 00515 if (loc == std::string::npos){ 00516 from = range; 00517 } 00518 else{ 00519 from = range.substr(0, loc); 00520 to = range.substr(loc+1, range.size()); 00521 } 00522 long a, b; 00523 std::istringstream iss1(from); 00524 iss1 >> a; 00525 b = a; 00526 if (to.size() > 0){ 00527 std::istringstream iss2(to); 00528 iss2 >> b; 00529 if (b < a) 00530 std::swap(from,to); 00531 } 00532 return (b != a) ? 2 : 1; 00533 } 00534 00535 00536 template <typename Integral> 00537 IntegerRangeListValidator<Integral>::IntegerRangeListValidator( 00538 bool unsorted): min_(1), max_(0), unsorted_(unsorted) 00539 { 00540 } 00541 00542 template <typename Integral> 00543 IntegerRangeListValidator<Integral>::IntegerRangeListValidator( 00544 Integral validMin, Integral validMax, bool unsorted) : 00545 min_(validMin), max_(validMax), unsorted_(unsorted) 00546 { 00547 if (min_ < max_) std::swap(min_,max_); 00548 } 00549 00550 // Implementation of ParameterEntryValidator interface 00551 00552 template <typename Integral> 00553 const std::string 00554 IntegerRangeListValidator<Integral>::getXMLTypeName() const 00555 { 00556 std::string className("IntegerRangeListValidator"); 00557 std::string classType("("+Teuchos::TypeNameTraits<Integral>::name()+")"); 00558 return std::string(className + classType); 00559 } 00560 00561 template <typename Integral> 00562 void IntegerRangeListValidator<Integral>::printDoc( 00563 std::string const& docString, std::ostream &out) const 00564 { 00565 Teuchos::StrUtils::printLines(out,"# ",docString); 00566 out << "#\tAn integer range list is a string which can contain:\n"; 00567 out << "#\t\tthe text \"all\", which indicates all values\n"; 00568 out << "#\t\ta list of integer ranges separated by commas.\n"; 00569 out << "#\tA range is one value, or two values separated by a dash.\n"; 00570 out << "#\tExample: \"all\" or \"1-10\" or \"3, 10-12\" or \"25\"\n"; 00571 if (max_ >= min_){ 00572 out << "#\tThe range of valid integers is ["; 00573 out << min_ << "," << max_ << "]\n"; 00574 } 00575 } 00576 00577 template <typename Integral> 00578 ValidStringsList IntegerRangeListValidator<Integral>::validStringValues() const 00579 { 00580 return Teuchos::null; 00581 } 00582 00583 template <typename Integral> 00584 void IntegerRangeListValidator<Integral>::validate( 00585 Teuchos::ParameterEntry const& entry, 00586 std::string const& paramName, std::string const& sublistName) const 00587 { 00588 if (!entry.isType<std::string>()){ 00589 return; // already converted to an an array 00590 } 00591 std::string *sptr=NULL; 00592 std::string &rangeList = entry.getValue(sptr); 00593 std::string inValue(rangeList); 00594 00595 if (listSaysAll(inValue)) 00596 return; // "all" is in the string 00597 00598 // throw error if invalid integer range list 00599 std::for_each(inValue.begin(), inValue.end(), checkValid); 00600 00601 if (max_ >= min_){ 00602 std::string::const_iterator rangeBegin = inValue.begin(); 00603 std::string::const_iterator valueEnd = inValue.end(); 00604 00605 while (rangeBegin != valueEnd){ 00606 std::string::const_iterator rangeEnd = std::search( 00607 rangeBegin, valueEnd, listDelim_.begin(), listDelim_.end()); 00608 std::string range(rangeBegin, rangeEnd); 00609 std::string aHalf, bHalf; 00610 int count = breakRange(range, aHalf, bHalf); 00611 00612 Integral a, b; 00613 std::istringstream iss1(aHalf); 00614 iss1 >> a; 00615 if (count > 1){ 00616 std::istringstream iss2(bHalf); 00617 iss2 >> b; 00618 } 00619 else 00620 b = a; 00621 00622 if ((a < min_) || (b > max_)){ 00623 std::ostringstream oss; 00624 oss << "input range [" << a << "," << b << "] "; 00625 oss << "exceeds valid range [" << min_ << "," << max_ << "] "; 00626 throw std::runtime_error(oss.str()); 00627 } 00628 if (rangeEnd == valueEnd) 00629 rangeBegin = rangeEnd; 00630 else 00631 rangeBegin = ++rangeEnd; 00632 } 00633 } 00634 } 00635 00636 template <typename Integral> 00637 void IntegerRangeListValidator<Integral>::validateAndModify( 00638 std::string const& paramName, std::string const& sublistName, 00639 Teuchos::ParameterEntry * entry) const 00640 { 00641 typedef typename Teuchos::Array<Integral>::size_type arraySize_t; 00642 if (!entry->isType<std::string>()){ 00643 return; 00644 } 00645 00646 std::string *sptr=NULL; 00647 std::string &rangeList = entry->getValue(sptr); 00648 Teuchos::Array<Integral> valueList; 00649 00650 std::string inValue(rangeList); 00651 00652 if (listSaysAll(inValue)){ 00653 valueList.push_back(RANGE_INCLUDES_ALL); 00654 } 00655 else{ 00656 // throw error if invalid integer range list 00657 std::for_each(inValue.begin(), inValue.end(), checkValid); 00658 00659 std::string::const_iterator rangeBegin = inValue.begin(); 00660 std::string::const_iterator valueEnd = inValue.end(); 00661 00662 while (rangeBegin != valueEnd){ 00663 std::string::const_iterator rangeEnd = std::search(rangeBegin, 00664 valueEnd, listDelim_.begin(), listDelim_.end()); 00665 std::string range(rangeBegin, rangeEnd); 00666 std::string aHalf, bHalf; 00667 int count = breakRange(range, aHalf, bHalf); 00668 00669 Integral a, b; 00670 std::istringstream iss1(aHalf); 00671 iss1 >> a; 00672 if (count > 1){ 00673 std::istringstream iss2(bHalf); 00674 iss2 >> b; 00675 } 00676 else 00677 b = a; 00678 00679 if ((max_ >= min_) && ((a < min_) || (b > max_))){ 00680 std::ostringstream oss; 00681 oss << "input range [" << a << "," << b << "] "; 00682 oss << "exceeds valid range [" << min_ << "," << max_ << "] "; 00683 throw std::runtime_error(oss.str()); 00684 } 00685 for (Integral i=a; i <=b; i++) 00686 valueList.push_back(i); 00687 if (rangeEnd == valueEnd) 00688 rangeBegin = rangeEnd; 00689 else 00690 rangeBegin = ++rangeEnd; 00691 } 00692 if (!unsorted_ && valueList.size() > 1){ // sort & remove duplicates 00693 std::sort(valueList.begin(), valueList.end()); 00694 arraySize_t listEnd = 0; 00695 arraySize_t length = valueList.size(); 00696 for (arraySize_t i=1; i < length; i++){ 00697 if (valueList[i] > valueList[listEnd]){ 00698 listEnd++; 00699 if (listEnd != i) 00700 valueList[listEnd] = valueList[i]; 00701 } 00702 } 00703 if (++listEnd < length) 00704 valueList.resize(listEnd); 00705 } 00706 00707 Integral flag = RANGE_IS_LISTED; 00708 if (valueList.size() == 0){ 00709 flag = RANGE_IS_EMPTY; 00710 } 00711 else if (max_ >= min_){ 00712 Integral allSize = max_ - min_ + 1; 00713 if (valueList.size() == allSize){ 00714 flag = RANGE_INCLUDES_ALL; 00715 valueList.clear(); 00716 } 00717 } 00718 valueList.push_back(flag); 00719 } 00720 entry->setValue(valueList); 00721 } 00722 00724 // Parameter entry validator <-> XML conversion 00726 00739 template <typename Integral> 00740 class IntegerRangeListValidatorXMLConverter : public Teuchos::ValidatorXMLConverter 00741 { 00742 00743 public: 00744 00745 RCP<Teuchos::ParameterEntryValidator> convertXML( 00746 const Teuchos::XMLObject& xmlObj, 00747 const Teuchos::IDtoValidatorMap& validatorIDsMap) const; 00748 00749 void convertValidator( 00750 const RCP<const Teuchos::ParameterEntryValidator> validator, 00751 Teuchos::XMLObject& xmlObj, 00752 const Teuchos::ValidatortoIDMap& validatorIDsMap) const; 00753 00754 #ifdef HAVE_TEUCHOS_DEBUG 00755 00756 RCP<const Teuchos::ParameterEntryValidator> getDummyValidator() const{ 00757 return Teuchos::DummyObjectGetter<IntegerRangeListValidator<Integral> >::getDummyObject(); 00758 } 00759 #endif 00760 }; 00761 00762 template <typename Integral> 00763 RCP<Teuchos::ParameterEntryValidator> 00764 IntegerRangeListValidatorXMLConverter<Integral>::convertXML( 00765 const Teuchos::XMLObject& xmlObj, 00766 const Teuchos::IDtoValidatorMap& /*validatorIDsMap*/) const 00767 { 00768 Integral minValue=0, maxValue=0; 00769 bool unsorted=false, hasMin=false, hasMax=false; 00770 00771 if (xmlObj.hasAttribute(std::string("min"))) { 00772 minValue = xmlObj.getRequired<Integral>(std::string("min")); 00773 hasMin = true; 00774 } 00775 00776 if (xmlObj.hasAttribute(std::string("max"))) { 00777 maxValue = xmlObj.getRequired<Integral>(std::string("max")); 00778 hasMax = true; 00779 } 00780 00781 if (xmlObj.hasAttribute(std::string("unsorted"))) 00782 unsorted = xmlObj.getRequired<bool>(std::string("unsorted")); 00783 00784 RCP<Teuchos::ParameterEntryValidator> toReturn; 00785 00786 if (hasMin && hasMax) 00787 toReturn = rcp(new IntegerRangeListValidator<Integral>(minValue, maxValue, unsorted)); 00788 else if (!hasMin && !hasMax) 00789 toReturn = rcp(new IntegerRangeListValidator<Integral>(unsorted)); 00790 else 00791 throw std::runtime_error("invalid XML representation"); 00792 00793 return toReturn; 00794 } 00795 00796 template<typename Integral> 00797 void IntegerRangeListValidatorXMLConverter<Integral>::convertValidator( 00798 const RCP<const Teuchos::ParameterEntryValidator > validator, 00799 Teuchos::XMLObject& xmlObj, 00800 const Teuchos::ValidatortoIDMap& /*validatorIDsMap*/) const 00801 { 00802 RCP<const IntegerRangeListValidator<Integral> > castedValidator = 00803 rcp_dynamic_cast<const IntegerRangeListValidator<Integral> >( 00804 validator, true); 00805 00806 Integral minValue = castedValidator->getAllowedMinimum(); 00807 Integral maxValue = castedValidator->getAllowedMaximum(); 00808 bool unsorted = castedValidator->inputListWillBeSorted(); 00809 00810 if (minValue < maxValue){ 00811 xmlObj.addAttribute<Integral>(std::string("min"), minValue); 00812 xmlObj.addAttribute<Integral>(std::string("max"), maxValue); 00813 } 00814 00815 xmlObj.addAttribute<bool>(std::string("unsorted"), unsorted); 00816 } 00817 00818 } 00819 // end of namespace Zoltan2 00820 00821 #endif
1.7.6.1