Zoltan2
Loading...
Searching...
No Matches
Zoltan2_IntegerRangeList.hpp
Go to the documentation of this file.
1// @HEADER
2//
3// ***********************************************************************
4//
5// Zoltan2: A package of combinatorial algorithms for scientific computing
6// Copyright 2012 Sandia Corporation
7//
8// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
9// the U.S. Government retains certain rights in this software.
10//
11// Redistribution and use in source and binary forms, with or without
12// modification, are permitted provided that the following conditions are
13// met:
14//
15// 1. Redistributions of source code must retain the above copyright
16// notice, this list of conditions and the following disclaimer.
17//
18// 2. Redistributions in binary form must reproduce the above copyright
19// notice, this list of conditions and the following disclaimer in the
20// documentation and/or other materials provided with the distribution.
21//
22// 3. Neither the name of the Corporation nor the names of the
23// contributors may be used to endorse or promote products derived from
24// this software without specific prior written permission.
25//
26// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
27// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
30// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
31// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
32// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
33// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
34// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
35// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
36// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37//
38// Questions? Contact Karen Devine (kddevin@sandia.gov)
39// Erik Boman (egboman@sandia.gov)
40// Siva Rajamanickam (srajama@sandia.gov)
41//
42// ***********************************************************************
43//
44// @HEADER
45
50#ifndef _ZOLTAN2_INTEGERRANGELIST_HPP_
51#define _ZOLTAN2_INTEGERRANGELIST_HPP_
52
53#include <Zoltan2_config.h>
54
55#include <Teuchos_ParameterEntryValidator.hpp>
56#include <Teuchos_ValidatorXMLConverter.hpp>
57#include <Teuchos_XMLObject.hpp>
58#include <Teuchos_ValidatorMaps.hpp>
59#include <Teuchos_DummyObjectGetter.hpp>
60#include <Teuchos_StrUtils.hpp>
61
62#ifdef _MSC_VER
63// for isspace(int), else one gets isspace(_Elem _Ch, const locale& _Loc) from <locale>
64#include <cctype>
65#endif
66
67// Had to redefine this type from Teuchos_ParameterEntryValidator.hpp.
68// Compiler stumbled on it.
69typedef Teuchos::RCP<const Teuchos::Array<std::string> > ValidStringsList;
70
71namespace Zoltan2{
72
82
83template <typename T> class IntegerRangeListValidator;
84
86// Helper functions for interpreting integer range list arrays.
88
95template <typename Integral>
96 bool validIntegralRangeList(const Teuchos::Array<Integral> &vals)
97{
98 typedef typename Teuchos::Array<Integral>::size_type arraySize_t;
99 arraySize_t len = vals.size();
100 if (len==0)
101 return false;
102
103 Integral flag = vals[len-1];
104 if ((flag != RANGE_INCLUDES_ALL) && (flag != RANGE_IS_EMPTY) &&
105 (flag != RANGE_IS_LISTED))
106 return false;
107
108 return true;
109}
110
125template <typename Integral>
126 bool allValuesAreInRangeList(const Teuchos::Array<Integral> &vals)
127{
128 if (!validIntegralRangeList(vals))
129 throw std::runtime_error("list is not a valid range list");
130 return vals[vals.size()-1] == RANGE_INCLUDES_ALL;
131}
132
147template <typename Integral>
148 bool allValuesAreInRangeList(const Teuchos::ParameterEntry &e)
149{
150 if (!e.isType<Teuchos::Array<Integral> >())
151 throw std::runtime_error("Should not call until modified");
152
153 Teuchos::Array<Integral> *valPtr=NULL;
154 Teuchos::Array<Integral> &vals = e.getValue(valPtr);
155 return allValuesAreInRangeList(vals);
156}
157
172template <typename Integral>
173 bool noValuesAreInRangeList(const Teuchos::Array<Integral> &vals)
174{
175 if (!validIntegralRangeList(vals))
176 throw std::runtime_error("list is not a valid range list");
177 return vals[vals.size()-1] == RANGE_IS_EMPTY;
178}
179
194template <typename Integral>
195 bool noValuesAreInRangeList(const Teuchos::ParameterEntry &e)
196{
197 if (!e.isType<Teuchos::Array<Integral> >())
198 throw std::runtime_error("Should not call until modified");
199
200 Teuchos::Array<Integral> *valPtr=NULL;
201 Teuchos::Array<Integral> &vals = e.getValue(valPtr);
202 return noValuesAreInRangeList(vals);
203}
204
205// TODO :
206// inList(std::vector<Integral> &val, std::vector<bool> &result)
207
219template <typename Integral>
220 bool IsInRangeList(const Integral val, const Teuchos::Array<Integral> &valList, bool sorted=true)
221{
222 if (allValuesAreInRangeList(valList))
223 return true;
224 else if (noValuesAreInRangeList(valList))
225 return false;
226
227 if (sorted){
228 typename Teuchos::Array<Integral>::const_iterator flag = valList.end();
229 --flag;
230 if (std::binary_search(valList.begin(), flag, val))
231 return true;
232 else
233 return false;
234 }
235 else{
236 for (typename Teuchos::Array<Integral>::size_type i=0; i < valList.size()-1; i++){
237 if (valList[i] == val)
238 return true;
239 }
240 return false;
241 }
242}
243
254template <typename Integral>
255 bool IsInRangeList(const Integral val, const Teuchos::ParameterEntry &e)
256{
257 if (!e.isType<Teuchos::Array<Integral> >())
258 throw std::runtime_error("Should not call until modified");
259
260 Teuchos::Array<Integral> *valPtr=NULL;
261 Teuchos::Array<Integral> &valList = e.getValue(valPtr);
262
263 typedef IntegerRangeListValidator<Integral> irl_t;
264 RCP<const irl_t> irl;
265 bool fail = false;
266
267 RCP<const Teuchos::ParameterEntryValidator> valtor = e.validator();
268 if (!valtor.is_null()){
269 try{
270 irl = rcp_dynamic_cast<const irl_t>(valtor);
271 }
272 catch (...){
273 fail = true;
274 }
275 }
276 else{
277 fail = true;
278 }
279
280 if (fail)
281 throw std::runtime_error("wrong type of parameter entry");
282
283 bool sorted = irl->inputListWillBeSorted();
284
285 return IsInRangeList(val, valList, sorted);
286}
287
296template <typename Integral>
297 Teuchos::ArrayView<Integral> getList(Teuchos::Array<Integral> &irl)
298{
299 Teuchos::ArrayView<Integral> av; // av.size() == 0
300
303 av = irl.view(0, irl.size()-1); // skip last value, it's a flag
304
305 return av;
306}
307
316template <typename Integral>
317 void printIntegralRangeList(std::ostream &os, Teuchos::Array<Integral> &irl)
318{
320 os << "all";
322 os << "empty";
323 else{
324 Teuchos::ArrayView<const Integral> view =
325 irl.view(0, irl.size()-1); // skip last value, it's a flag
326 os << view;
327 }
328}
329
331// Validator class
333
393template <typename Integral>
394 class IntegerRangeListValidator : public Teuchos::ParameterEntryValidator
395{
396private:
397
398#ifndef DOXYGEN_SHOULD_SKIP_THIS
399
400 Integral min_;
401 Integral max_;
402 bool unsorted_;
403
404 static const std::string listDelim_;
405 static const std::string rangeDelim_;
406 static const std::string allText_;
407
408 static void checkValid(char c);
409 static bool listSaysAll(std::string &l);
410 static int breakRange(std::string &range, std::string &from, std::string &to);
411
412#endif
413
414public:
420 IntegerRangeListValidator(bool unsorted=false);
421
431 IntegerRangeListValidator(Integral validMin, Integral validMax,
432 bool unsorted=false);
433
434 // Implementation of ParameterEntryValidator interface
435
436 const std::string getXMLTypeName() const;
437
438 void printDoc(std::string const& docString, std::ostream &out) const;
439
441
442 void validate( Teuchos::ParameterEntry const& entry,
443 std::string const& paramName, std::string const& sublistName
444 ) const;
445
446 void validateAndModify( std::string const& paramName,
447 std::string const& sublistName, Teuchos::ParameterEntry * entry
448 ) const;
449
450 // IntegerRangeListValidator methods
451
457 Integral getAllowedMinimum() const { return min_;}
458
464 Integral getAllowedMaximum() const { return max_;}
465
472 bool inputListWillBeSorted() const { return !unsorted_;}
473
474}; // end class
475
477// Class definitions
479
480template <typename Integral>
481const std::string IntegerRangeListValidator<Integral>::listDelim_(",");
482
483template <typename Integral>
484const std::string IntegerRangeListValidator<Integral>::rangeDelim_("-");
485
486template <typename Integral>
487const std::string IntegerRangeListValidator<Integral>::allText_("all");
488
489template <typename Integral>
490 void IntegerRangeListValidator<Integral>::checkValid(char c)
491{
492 if (std::isspace(c) || std::isdigit(c) || (c == ',') || (c == '-'))
493 return;
494 else
495 throw std::runtime_error("invalid integer range list");
496}
497
498template <typename Integral>
499 bool IntegerRangeListValidator<Integral>::listSaysAll(std::string &l)
500{
501 std::transform(l.begin(), l.end(), l.begin(), (int(*)(int)) tolower);
502 if (l.find(allText_) != std::string::npos)
503 return true; // "all" is in the string
504 else
505 return false;
506}
507
508template <typename Integral>
509 int IntegerRangeListValidator<Integral>::breakRange(
510 std::string &range, std::string &from, std::string &to)
511{
512 from.clear();
513 to.clear();
514 std::string::size_type loc = range.find(rangeDelim_);
515 if (loc == std::string::npos){
516 from = range;
517 }
518 else{
519 from = range.substr(0, loc);
520 to = range.substr(loc+1, range.size());
521 }
522 long a, b;
523 std::istringstream iss1(from);
524 iss1 >> a;
525 b = a;
526 if (to.size() > 0){
527 std::istringstream iss2(to);
528 iss2 >> b;
529 if (b < a)
530 std::swap(from,to);
531 }
532 return (b != a) ? 2 : 1;
533}
534
535
536template <typename Integral>
538 bool unsorted): min_(1), max_(0), unsorted_(unsorted)
539{
540}
541
542template <typename Integral>
544 Integral validMin, Integral validMax, bool unsorted) :
545 min_(validMin), max_(validMax), unsorted_(unsorted)
546{
547 if (min_ < max_) std::swap(min_,max_);
548}
549
550 // Implementation of ParameterEntryValidator interface
551
552template <typename Integral>
553 const std::string
555{
556 std::string className("IntegerRangeListValidator");
557 std::string classType("("+Teuchos::TypeNameTraits<Integral>::name()+")");
558 return std::string(className + classType);
559}
560
561template <typename Integral>
563 std::string const& docString, std::ostream &out) const
564{
565 Teuchos::StrUtils::printLines(out,"# ",docString);
566 out << "#\tAn integer range list is a string which can contain:\n";
567 out << "#\t\tthe text \"all\", which indicates all values\n";
568 out << "#\t\ta list of integer ranges separated by commas.\n";
569 out << "#\tA range is one value, or two values separated by a dash.\n";
570 out << "#\tExample: \"all\" or \"1-10\" or \"3, 10-12\" or \"25\"\n";
571 if (max_ >= min_){
572 out << "#\tThe range of valid integers is [";
573 out << min_ << "," << max_ << "]\n";
574 }
575}
576
577template <typename Integral>
582
583template <typename Integral>
585 Teuchos::ParameterEntry const& entry,
586 std::string const& /* paramName */, std::string const& /* sublistName */) const
587{
588 if (!entry.isType<std::string>()){
589 return; // already converted to an an array
590 }
591 std::string *sptr=NULL;
592 std::string &rangeList = entry.getValue(sptr);
593 std::string inValue(rangeList);
594
595 if (listSaysAll(inValue))
596 return; // "all" is in the string
597
598 // throw error if invalid integer range list
599 std::for_each(inValue.begin(), inValue.end(), checkValid);
600
601 if (max_ >= min_){
602 std::string::const_iterator rangeBegin = inValue.begin();
603 std::string::const_iterator valueEnd = inValue.end();
604
605 while (rangeBegin != valueEnd){
606 std::string::const_iterator rangeEnd = std::search(
607 rangeBegin, valueEnd, listDelim_.begin(), listDelim_.end());
608 std::string range(rangeBegin, rangeEnd);
609 std::string aHalf, bHalf;
610 int count = breakRange(range, aHalf, bHalf);
611
612 Integral a, b;
613 std::istringstream iss1(aHalf);
614 iss1 >> a;
615 if (count > 1){
616 std::istringstream iss2(bHalf);
617 iss2 >> b;
618 }
619 else
620 b = a;
621
622 if ((a < min_) || (b > max_)){
623 std::ostringstream oss;
624 oss << "input range [" << a << "," << b << "] ";
625 oss << "exceeds valid range [" << min_ << "," << max_ << "] ";
626 throw std::runtime_error(oss.str());
627 }
628 if (rangeEnd == valueEnd)
629 rangeBegin = rangeEnd;
630 else
631 rangeBegin = ++rangeEnd;
632 }
633 }
634}
635
636template <typename Integral>
638 std::string const& /* paramName */, std::string const& /* sublistName */,
639 Teuchos::ParameterEntry * entry) const
640{
641 typedef typename Teuchos::Array<Integral>::size_type arraySize_t;
642 if (!entry->isType<std::string>()){
643 return;
644 }
645
646 std::string *sptr=NULL;
647 std::string &rangeList = entry->getValue(sptr);
648 Teuchos::Array<Integral> valueList;
649
650 std::string inValue(rangeList);
651
652 if (listSaysAll(inValue)){
653 valueList.push_back(RANGE_INCLUDES_ALL);
654 }
655 else{
656 // throw error if invalid integer range list
657 std::for_each(inValue.begin(), inValue.end(), checkValid);
658
659 std::string::const_iterator rangeBegin = inValue.begin();
660 std::string::const_iterator valueEnd = inValue.end();
661
662 while (rangeBegin != valueEnd){
663 std::string::const_iterator rangeEnd = std::search(rangeBegin,
664 valueEnd, listDelim_.begin(), listDelim_.end());
665 std::string range(rangeBegin, rangeEnd);
666 std::string aHalf, bHalf;
667 int count = breakRange(range, aHalf, bHalf);
668
669 Integral a, b;
670 std::istringstream iss1(aHalf);
671 iss1 >> a;
672 if (count > 1){
673 std::istringstream iss2(bHalf);
674 iss2 >> b;
675 }
676 else
677 b = a;
678
679 if ((max_ >= min_) && ((a < min_) || (b > max_))){
680 std::ostringstream oss;
681 oss << "input range [" << a << "," << b << "] ";
682 oss << "exceeds valid range [" << min_ << "," << max_ << "] ";
683 throw std::runtime_error(oss.str());
684 }
685 for (Integral i=a; i <=b; i++)
686 valueList.push_back(i);
687 if (rangeEnd == valueEnd)
688 rangeBegin = rangeEnd;
689 else
690 rangeBegin = ++rangeEnd;
691 }
692 if (!unsorted_ && valueList.size() > 1){ // sort & remove duplicates
693 std::sort(valueList.begin(), valueList.end());
694 arraySize_t listEnd = 0;
695 arraySize_t length = valueList.size();
696 for (arraySize_t i=1; i < length; i++){
697 if (valueList[i] > valueList[listEnd]){
698 listEnd++;
699 if (listEnd != i)
700 valueList[listEnd] = valueList[i];
701 }
702 }
703 if (++listEnd < length)
704 valueList.resize(listEnd);
705 }
706
707 Integral flag = RANGE_IS_LISTED;
708 if (valueList.size() == 0){
709 flag = RANGE_IS_EMPTY;
710 }
711 else if (max_ >= min_){
712 Integral allSize = max_ - min_ + 1;
713 if (valueList.size() == allSize){
714 flag = RANGE_INCLUDES_ALL;
715 valueList.clear();
716 }
717 }
718 valueList.push_back(flag);
719 }
720 entry->setValue(valueList);
721}
722
724// Parameter entry validator <-> XML conversion
726
739template <typename Integral>
740class IntegerRangeListValidatorXMLConverter : public Teuchos::ValidatorXMLConverter
741{
742
743public:
744
745 RCP<Teuchos::ParameterEntryValidator> convertXML(
746 const Teuchos::XMLObject& xmlObj,
747 const Teuchos::IDtoValidatorMap& validatorIDsMap) const;
748
749 void convertValidator(
750 const RCP<const Teuchos::ParameterEntryValidator> validator,
751 Teuchos::XMLObject& xmlObj,
752 const Teuchos::ValidatortoIDMap& validatorIDsMap) const;
753
754#ifdef HAVE_TEUCHOS_DEBUG
756 RCP<const Teuchos::ParameterEntryValidator> getDummyValidator() const{
757 return Teuchos::DummyObjectGetter<IntegerRangeListValidator<Integral> >::getDummyObject();
758 }
759#endif
760};
761
762template <typename Integral>
763 RCP<Teuchos::ParameterEntryValidator>
765 const Teuchos::XMLObject& xmlObj,
766 const Teuchos::IDtoValidatorMap& /*validatorIDsMap*/) const
767{
768 Integral minValue=0, maxValue=0;
769 bool unsorted=false, hasMin=false, hasMax=false;
770
771 if (xmlObj.hasAttribute(std::string("min"))) {
772 minValue = xmlObj.getRequired<Integral>(std::string("min"));
773 hasMin = true;
774 }
775
776 if (xmlObj.hasAttribute(std::string("max"))) {
777 maxValue = xmlObj.getRequired<Integral>(std::string("max"));
778 hasMax = true;
779 }
780
781 if (xmlObj.hasAttribute(std::string("unsorted")))
782 unsorted = xmlObj.getRequired<bool>(std::string("unsorted"));
783
784 RCP<Teuchos::ParameterEntryValidator> toReturn;
785
786 if (hasMin && hasMax)
787 toReturn = rcp(new IntegerRangeListValidator<Integral>(minValue, maxValue, unsorted));
788 else if (!hasMin && !hasMax)
789 toReturn = rcp(new IntegerRangeListValidator<Integral>(unsorted));
790 else
791 throw std::runtime_error("invalid XML representation");
792
793 return toReturn;
794}
795
796template<typename Integral>
798 const RCP<const Teuchos::ParameterEntryValidator > validator,
799 Teuchos::XMLObject& xmlObj,
800 const Teuchos::ValidatortoIDMap& /*validatorIDsMap*/) const
801{
802 RCP<const IntegerRangeListValidator<Integral> > castedValidator =
803 rcp_dynamic_cast<const IntegerRangeListValidator<Integral> >(
804 validator, true);
805
806 Integral minValue = castedValidator->getAllowedMinimum();
807 Integral maxValue = castedValidator->getAllowedMaximum();
808 bool unsorted = castedValidator->inputListWillBeSorted();
809
810 if (minValue < maxValue){
811 xmlObj.addAttribute<Integral>(std::string("min"), minValue);
812 xmlObj.addAttribute<Integral>(std::string("max"), maxValue);
813 }
814
815 xmlObj.addAttribute<bool>(std::string("unsorted"), unsorted);
816}
817
818}
819 // end of namespace Zoltan2
820
821#endif
Teuchos::RCP< const Teuchos::Array< std::string > > ValidStringsList
XML conversion code for IntegerRangeListValidator.
RCP< Teuchos::ParameterEntryValidator > convertXML(const Teuchos::XMLObject &xmlObj, const Teuchos::IDtoValidatorMap &validatorIDsMap) const
void convertValidator(const RCP< const Teuchos::ParameterEntryValidator > validator, Teuchos::XMLObject &xmlObj, const Teuchos::ValidatortoIDMap &validatorIDsMap) const
A ParameterList validator for integer range lists.
void printDoc(std::string const &docString, std::ostream &out) const
Integral getAllowedMaximum() const
Return the maximum value permitted in the list.
Integral getAllowedMinimum() const
Return the minimum value permitted in the list.
IntegerRangeListValidator(bool unsorted=false)
Constructor: any Integral is valid.
void validate(Teuchos::ParameterEntry const &entry, std::string const &paramName, std::string const &sublistName) const
void validateAndModify(std::string const &paramName, std::string const &sublistName, Teuchos::ParameterEntry *entry) const
bool inputListWillBeSorted() const
Return whether the list is sorted or not.
Created by mbenlioglu on Aug 31, 2020.
bool noValuesAreInRangeList(const Teuchos::Array< Integral > &vals)
A helper function that determines if no values are in the list.
static const std::string fail
bool allValuesAreInRangeList(const Teuchos::Array< Integral > &vals)
A helper function that determines if all values are in the list.
bool IsInRangeList(const Integral val, const Teuchos::Array< Integral > &valList, bool sorted=true)
A helper function that determines if a value is in the list.
void printIntegralRangeList(std::ostream &os, Teuchos::Array< Integral > &irl)
A helper function that prints the meaning of an encoded integer range list.
RangeType
Codes that indicate how to interpret the Array<int> representing the user's integer range list.
@ RANGE_INCLUDES_ALL
all values were listed
@ RANGE_IS_LISTED
the listed values are in the Array<int>
@ RANGE_IS_EMPTY
no values were listed
bool validIntegralRangeList(const Teuchos::Array< Integral > &vals)
A helper function that indicates whether an array is a valid integer range list.
Teuchos::ArrayView< Integral > getList(Teuchos::Array< Integral > &irl)
A helper function that returns a view of the list.