Zoltan2
Loading...
Searching...
No Matches
Zoltan2_IntegerRangeList.hpp
Go to the documentation of this file.
1// @HEADER
2// *****************************************************************************
3// Zoltan2: A package of combinatorial algorithms for scientific computing
4//
5// Copyright 2012 NTESS and the Zoltan2 contributors.
6// SPDX-License-Identifier: BSD-3-Clause
7// *****************************************************************************
8// @HEADER
9
14#ifndef _ZOLTAN2_INTEGERRANGELIST_HPP_
15#define _ZOLTAN2_INTEGERRANGELIST_HPP_
16
17#include <Zoltan2_config.h>
18
19#include <Teuchos_ParameterEntryValidator.hpp>
20#include <Teuchos_ValidatorXMLConverter.hpp>
21#include <Teuchos_XMLObject.hpp>
22#include <Teuchos_ValidatorMaps.hpp>
23#include <Teuchos_DummyObjectGetter.hpp>
24#include <Teuchos_StrUtils.hpp>
25
26#ifdef _MSC_VER
27// for isspace(int), else one gets isspace(_Elem _Ch, const locale& _Loc) from <locale>
28#include <cctype>
29#endif
30
31// Had to redefine this type from Teuchos_ParameterEntryValidator.hpp.
32// Compiler stumbled on it.
33typedef Teuchos::RCP<const Teuchos::Array<std::string> > ValidStringsList;
34
35namespace Zoltan2{
36
46
47template <typename T> class IntegerRangeListValidator;
48
50// Helper functions for interpreting integer range list arrays.
52
59template <typename Integral>
60 bool validIntegralRangeList(const Teuchos::Array<Integral> &vals)
61{
62 typedef typename Teuchos::Array<Integral>::size_type arraySize_t;
63 arraySize_t len = vals.size();
64 if (len==0)
65 return false;
66
67 Integral flag = vals[len-1];
68 if ((flag != RANGE_INCLUDES_ALL) && (flag != RANGE_IS_EMPTY) &&
69 (flag != RANGE_IS_LISTED))
70 return false;
71
72 return true;
73}
74
89template <typename Integral>
90 bool allValuesAreInRangeList(const Teuchos::Array<Integral> &vals)
91{
92 if (!validIntegralRangeList(vals))
93 throw std::runtime_error("list is not a valid range list");
94 return vals[vals.size()-1] == RANGE_INCLUDES_ALL;
95}
96
111template <typename Integral>
112 bool allValuesAreInRangeList(const Teuchos::ParameterEntry &e)
113{
114 if (!e.isType<Teuchos::Array<Integral> >())
115 throw std::runtime_error("Should not call until modified");
116
117 Teuchos::Array<Integral> *valPtr=NULL;
118 Teuchos::Array<Integral> &vals = e.getValue(valPtr);
119 return allValuesAreInRangeList(vals);
120}
121
136template <typename Integral>
137 bool noValuesAreInRangeList(const Teuchos::Array<Integral> &vals)
138{
139 if (!validIntegralRangeList(vals))
140 throw std::runtime_error("list is not a valid range list");
141 return vals[vals.size()-1] == RANGE_IS_EMPTY;
142}
143
158template <typename Integral>
159 bool noValuesAreInRangeList(const Teuchos::ParameterEntry &e)
160{
161 if (!e.isType<Teuchos::Array<Integral> >())
162 throw std::runtime_error("Should not call until modified");
163
164 Teuchos::Array<Integral> *valPtr=NULL;
165 Teuchos::Array<Integral> &vals = e.getValue(valPtr);
166 return noValuesAreInRangeList(vals);
167}
168
169// TODO :
170// inList(std::vector<Integral> &val, std::vector<bool> &result)
171
183template <typename Integral>
184 bool IsInRangeList(const Integral val, const Teuchos::Array<Integral> &valList, bool sorted=true)
185{
186 if (allValuesAreInRangeList(valList))
187 return true;
188 else if (noValuesAreInRangeList(valList))
189 return false;
190
191 if (sorted){
192 typename Teuchos::Array<Integral>::const_iterator flag = valList.end();
193 --flag;
194 if (std::binary_search(valList.begin(), flag, val))
195 return true;
196 else
197 return false;
198 }
199 else{
200 for (typename Teuchos::Array<Integral>::size_type i=0; i < valList.size()-1; i++){
201 if (valList[i] == val)
202 return true;
203 }
204 return false;
205 }
206}
207
218template <typename Integral>
219 bool IsInRangeList(const Integral val, const Teuchos::ParameterEntry &e)
220{
221 if (!e.isType<Teuchos::Array<Integral> >())
222 throw std::runtime_error("Should not call until modified");
223
224 Teuchos::Array<Integral> *valPtr=NULL;
225 Teuchos::Array<Integral> &valList = e.getValue(valPtr);
226
228 RCP<const irl_t> irl;
229 bool fail = false;
230
231 RCP<const Teuchos::ParameterEntryValidator> valtor = e.validator();
232 if (!valtor.is_null()){
233 try{
234 irl = rcp_dynamic_cast<const irl_t>(valtor);
235 }
236 catch (...){
237 fail = true;
238 }
239 }
240 else{
241 fail = true;
242 }
243
244 if (fail)
245 throw std::runtime_error("wrong type of parameter entry");
246
247 bool sorted = irl->inputListWillBeSorted();
248
249 return IsInRangeList(val, valList, sorted);
250}
251
260template <typename Integral>
261 Teuchos::ArrayView<Integral> getList(Teuchos::Array<Integral> &irl)
262{
263 Teuchos::ArrayView<Integral> av; // av.size() == 0
264
267 av = irl.view(0, irl.size()-1); // skip last value, it's a flag
268
269 return av;
270}
271
280template <typename Integral>
281 void printIntegralRangeList(std::ostream &os, Teuchos::Array<Integral> &irl)
282{
284 os << "all";
286 os << "empty";
287 else{
288 Teuchos::ArrayView<const Integral> view =
289 irl.view(0, irl.size()-1); // skip last value, it's a flag
290 os << view;
291 }
292}
293
295// Validator class
297
357template <typename Integral>
358 class IntegerRangeListValidator : public Teuchos::ParameterEntryValidator
359{
360private:
361
362#ifndef DOXYGEN_SHOULD_SKIP_THIS
363
364 Integral min_;
365 Integral max_;
366 bool unsorted_;
367
368 static const std::string listDelim_;
369 static const std::string rangeDelim_;
370 static const std::string allText_;
371
372 static void checkValid(char c);
373 static bool listSaysAll(std::string &l);
374 static int breakRange(std::string &range, std::string &from, std::string &to);
375
376#endif
377
378public:
384 IntegerRangeListValidator(bool unsorted=false);
385
395 IntegerRangeListValidator(Integral validMin, Integral validMax,
396 bool unsorted=false);
397
398 // Implementation of ParameterEntryValidator interface
399
400 const std::string getXMLTypeName() const;
401
402 void printDoc(std::string const& docString, std::ostream &out) const;
403
405
406 void validate( Teuchos::ParameterEntry const& entry,
407 std::string const& paramName, std::string const& sublistName
408 ) const;
409
410 void validateAndModify( std::string const& paramName,
411 std::string const& sublistName, Teuchos::ParameterEntry * entry
412 ) const;
413
414 // IntegerRangeListValidator methods
415
421 Integral getAllowedMinimum() const { return min_;}
422
428 Integral getAllowedMaximum() const { return max_;}
429
436 bool inputListWillBeSorted() const { return !unsorted_;}
437
438}; // end class
439
441// Class definitions
443
444template <typename Integral>
445const std::string IntegerRangeListValidator<Integral>::listDelim_(",");
446
447template <typename Integral>
448const std::string IntegerRangeListValidator<Integral>::rangeDelim_("-");
449
450template <typename Integral>
451const std::string IntegerRangeListValidator<Integral>::allText_("all");
452
453template <typename Integral>
454 void IntegerRangeListValidator<Integral>::checkValid(char c)
455{
456 if (std::isspace(c) || std::isdigit(c) || (c == ',') || (c == '-'))
457 return;
458 else
459 throw std::runtime_error("invalid integer range list");
460}
461
462template <typename Integral>
463 bool IntegerRangeListValidator<Integral>::listSaysAll(std::string &l)
464{
465 std::transform(l.begin(), l.end(), l.begin(), (int(*)(int)) tolower);
466 if (l.find(allText_) != std::string::npos)
467 return true; // "all" is in the string
468 else
469 return false;
470}
471
472template <typename Integral>
473 int IntegerRangeListValidator<Integral>::breakRange(
474 std::string &range, std::string &from, std::string &to)
475{
476 from.clear();
477 to.clear();
478 std::string::size_type loc = range.find(rangeDelim_);
479 if (loc == std::string::npos){
480 from = range;
481 }
482 else{
483 from = range.substr(0, loc);
484 to = range.substr(loc+1, range.size());
485 }
486 long a, b;
487 std::istringstream iss1(from);
488 iss1 >> a;
489 b = a;
490 if (to.size() > 0){
491 std::istringstream iss2(to);
492 iss2 >> b;
493 if (b < a)
494 std::swap(from,to);
495 }
496 return (b != a) ? 2 : 1;
497}
498
499
500template <typename Integral>
502 bool unsorted): min_(1), max_(0), unsorted_(unsorted)
503{
504}
505
506template <typename Integral>
508 Integral validMin, Integral validMax, bool unsorted) :
509 min_(validMin), max_(validMax), unsorted_(unsorted)
510{
511 if (min_ < max_) std::swap(min_,max_);
512}
513
514 // Implementation of ParameterEntryValidator interface
515
516template <typename Integral>
517 const std::string
519{
520 std::string className("IntegerRangeListValidator");
521 std::string classType("("+Teuchos::TypeNameTraits<Integral>::name()+")");
522 return std::string(className + classType);
523}
524
525template <typename Integral>
527 std::string const& docString, std::ostream &out) const
528{
529 Teuchos::StrUtils::printLines(out,"# ",docString);
530 out << "#\tAn integer range list is a string which can contain:\n";
531 out << "#\t\tthe text \"all\", which indicates all values\n";
532 out << "#\t\ta list of integer ranges separated by commas.\n";
533 out << "#\tA range is one value, or two values separated by a dash.\n";
534 out << "#\tExample: \"all\" or \"1-10\" or \"3, 10-12\" or \"25\"\n";
535 if (max_ >= min_){
536 out << "#\tThe range of valid integers is [";
537 out << min_ << "," << max_ << "]\n";
538 }
539}
540
541template <typename Integral>
546
547template <typename Integral>
549 Teuchos::ParameterEntry const& entry,
550 std::string const& /* paramName */, std::string const& /* sublistName */) const
551{
552 if (!entry.isType<std::string>()){
553 return; // already converted to an an array
554 }
555 std::string *sptr=NULL;
556 std::string &rangeList = entry.getValue(sptr);
557 std::string inValue(rangeList);
558
559 if (listSaysAll(inValue))
560 return; // "all" is in the string
561
562 // throw error if invalid integer range list
563 std::for_each(inValue.begin(), inValue.end(), checkValid);
564
565 if (max_ >= min_){
566 std::string::const_iterator rangeBegin = inValue.begin();
567 std::string::const_iterator valueEnd = inValue.end();
568
569 while (rangeBegin != valueEnd){
570 std::string::const_iterator rangeEnd = std::search(
571 rangeBegin, valueEnd, listDelim_.begin(), listDelim_.end());
572 std::string range(rangeBegin, rangeEnd);
573 std::string aHalf, bHalf;
574 int count = breakRange(range, aHalf, bHalf);
575
576 Integral a, b;
577 std::istringstream iss1(aHalf);
578 iss1 >> a;
579 if (count > 1){
580 std::istringstream iss2(bHalf);
581 iss2 >> b;
582 }
583 else
584 b = a;
585
586 if ((a < min_) || (b > max_)){
587 std::ostringstream oss;
588 oss << "input range [" << a << "," << b << "] ";
589 oss << "exceeds valid range [" << min_ << "," << max_ << "] ";
590 throw std::runtime_error(oss.str());
591 }
592 if (rangeEnd == valueEnd)
593 rangeBegin = rangeEnd;
594 else
595 rangeBegin = ++rangeEnd;
596 }
597 }
598}
599
600template <typename Integral>
602 std::string const& /* paramName */, std::string const& /* sublistName */,
603 Teuchos::ParameterEntry * entry) const
604{
605 typedef typename Teuchos::Array<Integral>::size_type arraySize_t;
606 if (!entry->isType<std::string>()){
607 return;
608 }
609
610 std::string *sptr=NULL;
611 std::string &rangeList = entry->getValue(sptr);
612 Teuchos::Array<Integral> valueList;
613
614 std::string inValue(rangeList);
615
616 if (listSaysAll(inValue)){
617 valueList.push_back(RANGE_INCLUDES_ALL);
618 }
619 else{
620 // throw error if invalid integer range list
621 std::for_each(inValue.begin(), inValue.end(), checkValid);
622
623 std::string::const_iterator rangeBegin = inValue.begin();
624 std::string::const_iterator valueEnd = inValue.end();
625
626 while (rangeBegin != valueEnd){
627 std::string::const_iterator rangeEnd = std::search(rangeBegin,
628 valueEnd, listDelim_.begin(), listDelim_.end());
629 std::string range(rangeBegin, rangeEnd);
630 std::string aHalf, bHalf;
631 int count = breakRange(range, aHalf, bHalf);
632
633 Integral a, b;
634 std::istringstream iss1(aHalf);
635 iss1 >> a;
636 if (count > 1){
637 std::istringstream iss2(bHalf);
638 iss2 >> b;
639 }
640 else
641 b = a;
642
643 if ((max_ >= min_) && ((a < min_) || (b > max_))){
644 std::ostringstream oss;
645 oss << "input range [" << a << "," << b << "] ";
646 oss << "exceeds valid range [" << min_ << "," << max_ << "] ";
647 throw std::runtime_error(oss.str());
648 }
649 for (Integral i=a; i <=b; i++)
650 valueList.push_back(i);
651 if (rangeEnd == valueEnd)
652 rangeBegin = rangeEnd;
653 else
654 rangeBegin = ++rangeEnd;
655 }
656 if (!unsorted_ && valueList.size() > 1){ // sort & remove duplicates
657 std::sort(valueList.begin(), valueList.end());
658 arraySize_t listEnd = 0;
659 arraySize_t length = valueList.size();
660 for (arraySize_t i=1; i < length; i++){
661 if (valueList[i] > valueList[listEnd]){
662 listEnd++;
663 if (listEnd != i)
664 valueList[listEnd] = valueList[i];
665 }
666 }
667 if (++listEnd < length)
668 valueList.resize(listEnd);
669 }
670
671 Integral flag = RANGE_IS_LISTED;
672 if (valueList.size() == 0){
673 flag = RANGE_IS_EMPTY;
674 }
675 else if (max_ >= min_){
676 Integral allSize = max_ - min_ + 1;
677 if (valueList.size() == allSize){
678 flag = RANGE_INCLUDES_ALL;
679 valueList.clear();
680 }
681 }
682 valueList.push_back(flag);
683 }
684 entry->setValue(valueList);
685}
686
688// Parameter entry validator <-> XML conversion
690
703template <typename Integral>
704class IntegerRangeListValidatorXMLConverter : public Teuchos::ValidatorXMLConverter
705{
706
707public:
708
709 RCP<Teuchos::ParameterEntryValidator> convertXML(
710 const Teuchos::XMLObject& xmlObj,
711 const Teuchos::IDtoValidatorMap& validatorIDsMap) const;
712
713 void convertValidator(
714 const RCP<const Teuchos::ParameterEntryValidator> validator,
715 Teuchos::XMLObject& xmlObj,
716 const Teuchos::ValidatortoIDMap& validatorIDsMap) const;
717
718#ifdef HAVE_TEUCHOS_DEBUG
720 RCP<const Teuchos::ParameterEntryValidator> getDummyValidator() const{
721 return Teuchos::DummyObjectGetter<IntegerRangeListValidator<Integral> >::getDummyObject();
722 }
723#endif
724};
725
726template <typename Integral>
727 RCP<Teuchos::ParameterEntryValidator>
729 const Teuchos::XMLObject& xmlObj,
730 const Teuchos::IDtoValidatorMap& /*validatorIDsMap*/) const
731{
732 Integral minValue=0, maxValue=0;
733 bool unsorted=false, hasMin=false, hasMax=false;
734
735 if (xmlObj.hasAttribute(std::string("min"))) {
736 minValue = xmlObj.getRequired<Integral>(std::string("min"));
737 hasMin = true;
738 }
739
740 if (xmlObj.hasAttribute(std::string("max"))) {
741 maxValue = xmlObj.getRequired<Integral>(std::string("max"));
742 hasMax = true;
743 }
744
745 if (xmlObj.hasAttribute(std::string("unsorted")))
746 unsorted = xmlObj.getRequired<bool>(std::string("unsorted"));
747
748 RCP<Teuchos::ParameterEntryValidator> toReturn;
749
750 if (hasMin && hasMax)
751 toReturn = rcp(new IntegerRangeListValidator<Integral>(minValue, maxValue, unsorted));
752 else if (!hasMin && !hasMax)
753 toReturn = rcp(new IntegerRangeListValidator<Integral>(unsorted));
754 else
755 throw std::runtime_error("invalid XML representation");
756
757 return toReturn;
758}
759
760template<typename Integral>
762 const RCP<const Teuchos::ParameterEntryValidator > validator,
763 Teuchos::XMLObject& xmlObj,
764 const Teuchos::ValidatortoIDMap& /*validatorIDsMap*/) const
765{
766 RCP<const IntegerRangeListValidator<Integral> > castedValidator =
767 rcp_dynamic_cast<const IntegerRangeListValidator<Integral> >(
768 validator, true);
769
770 Integral minValue = castedValidator->getAllowedMinimum();
771 Integral maxValue = castedValidator->getAllowedMaximum();
772 bool unsorted = castedValidator->inputListWillBeSorted();
773
774 if (minValue < maxValue){
775 xmlObj.addAttribute<Integral>(std::string("min"), minValue);
776 xmlObj.addAttribute<Integral>(std::string("max"), maxValue);
777 }
778
779 xmlObj.addAttribute<bool>(std::string("unsorted"), unsorted);
780}
781
782}
783 // end of namespace Zoltan2
784
785#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.