Zoltan2
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
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.
33 typedef Teuchos::RCP<const Teuchos::Array<std::string> > ValidStringsList;
34 
35 namespace Zoltan2{
36 
40 enum RangeType {
45 };
46 
47 template <typename T> class IntegerRangeListValidator;
48 
50 // Helper functions for interpreting integer range list arrays.
52 
59 template <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 
89 template <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 
111 template <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 
136 template <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 
158 template <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 
183 template <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 
218 template <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 
260 template <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 
280 template <typename Integral>
281  void printIntegralRangeList(std::ostream &os, Teuchos::Array<Integral> &irl)
282 {
284  os << "all";
285  else if (Zoltan2::noValuesAreInRangeList(irl))
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 
357 template <typename Integral>
358  class IntegerRangeListValidator : public Teuchos::ParameterEntryValidator
359 {
360 private:
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 
378 public:
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 
444 template <typename Integral>
445 const std::string IntegerRangeListValidator<Integral>::listDelim_(",");
446 
447 template <typename Integral>
448 const std::string IntegerRangeListValidator<Integral>::rangeDelim_("-");
449 
450 template <typename Integral>
451 const std::string IntegerRangeListValidator<Integral>::allText_("all");
452 
453 template <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 
462 template <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 
472 template <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 
500 template <typename Integral>
502  bool unsorted): min_(1), max_(0), unsorted_(unsorted)
503 {
504 }
505 
506 template <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 
516 template <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 
525 template <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 
541 template <typename Integral>
543 {
544  return Teuchos::null;
545 }
546 
547 template <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 
600 template <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 
703 template <typename Integral>
704 class IntegerRangeListValidatorXMLConverter : public Teuchos::ValidatorXMLConverter
705 {
706 
707 public:
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
719 
720  RCP<const Teuchos::ParameterEntryValidator> getDummyValidator() const{
721  return Teuchos::DummyObjectGetter<IntegerRangeListValidator<Integral> >::getDummyObject();
722  }
723 #endif
724 };
725 
726 template <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 
760 template<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
void validateAndModify(std::string const &paramName, std::string const &sublistName, Teuchos::ParameterEntry *entry) const
the listed values are in the Array&lt;int&gt;
Integral getAllowedMinimum() const
Return the minimum value permitted in the list.
XML conversion code for IntegerRangeListValidator.
RangeType
Codes that indicate how to interpret the Array&lt;int&gt; representing the user&#39;s integer range list...
void convertValidator(const RCP< const Teuchos::ParameterEntryValidator > validator, Teuchos::XMLObject &xmlObj, const Teuchos::ValidatortoIDMap &validatorIDsMap) const
A ParameterList validator for integer range lists.
bool validIntegralRangeList(const Teuchos::Array< Integral > &vals)
A helper function that indicates whether an array is a valid integer range list.
Integral getAllowedMaximum() const
Return the maximum value permitted 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.
Teuchos::RCP< const Teuchos::Array< std::string > > ValidStringsList
static const std::string fail
void validate(Teuchos::ParameterEntry const &entry, std::string const &paramName, std::string const &sublistName) const
bool noValuesAreInRangeList(const Teuchos::Array< Integral > &vals)
A helper function that determines if no values are in the list.
IntegerRangeListValidator(bool unsorted=false)
Constructor: any Integral is valid.
void printIntegralRangeList(std::ostream &os, Teuchos::Array< Integral > &irl)
A helper function that prints the meaning of an encoded integer range list.
Teuchos::ArrayView< Integral > getList(Teuchos::Array< Integral > &irl)
A helper function that returns a view of the list.
bool inputListWillBeSorted() const
Return whether the list is sorted or not.
void printDoc(std::string const &docString, std::ostream &out) const
RCP< Teuchos::ParameterEntryValidator > convertXML(const Teuchos::XMLObject &xmlObj, const Teuchos::IDtoValidatorMap &validatorIDsMap) const
bool allValuesAreInRangeList(const Teuchos::Array< Integral > &vals)
A helper function that determines if all values are in the list.