Source code for gerrychain.constraints.bounds

[docs]class Bounds: """ Wrapper for numeric-validators to enforce upper and lower limits. This class is meant to be called as a function after instantiation; its return is ``True`` if the numeric validator is within set limits, and ``False`` otherwise. """ def __init__(self, func, bounds): """ :param func: Numeric validator function. Should return an iterable of values. :param bounds: Tuple of (lower, upper) numeric bounds. """ self.func = func self.bounds = bounds def __call__(self, *args, **kwargs): lower, upper = self.bounds values = self.func(*args, **kwargs) return lower <= min(values) and max(values) <= upper @property def __name__(self): return "Bounds({},{})".format(self.func.__name__, str(self.bounds))
[docs]class UpperBound: """ Wrapper for numeric-validators to enforce upper limits. This class is meant to be called as a function after instantiation; its return is ``True`` if the numeric validator is within a set upper limit, and ``False`` otherwise. """ def __init__(self, func, bound): """ :param func: Numeric validator function. Should return a comparable value. :param bounds: Comparable upper bound. """ self.func = func self.bound = bound def __call__(self, *args, **kwargs): return self.func(*args, **kwargs) <= self.bound @property def __name__(self): return "UpperBound({} >= {})".format(self.func.__name__, self.bound) def __repr__(self): return "<{}>".format(self.__name__)
[docs]class LowerBound: """ Wrapper for numeric-validators to enforce lower limits. This class is meant to be called as a function after instantiation; its return is ``True`` if the numeric validator is within a set lower limit, and ``False`` otherwise. """ def __init__(self, func, bound): """ :param func: Numeric validator function. Should return a comparable value. :param bounds: Comparable lower bound. """ self.func = func self.bound = bound def __call__(self, *args, **kwargs): return self.func(*args, **kwargs) >= self.bound @property def __name__(self): return "LowerBound({} <= {})".format(self.func.__name__, self.bound) def __repr__(self): return "<{}>".format(self.__name__)
[docs]class SelfConfiguringUpperBound: """ Wrapper for numeric-validators to enforce automatic upper limits. When instantiated, the initial upper bound is set as the initial value of the numeric-validator. This class is meant to be called as a function after instantiation; its return is ``True`` if the numeric validator is within a set upper limit, and ``False`` otherwise. """ def __init__(self, func): """ :param func: Numeric validator function. """ self.func = func self.bound = None def __call__(self, partition): if not self.bound: self.bound = self.func(partition) return self.func(partition) <= self.bound
[docs]class SelfConfiguringLowerBound: """ Wrapper for numeric-validators to enforce automatic lower limits. When instantiated, the initial lower bound is set as the initial value of the numeric-validator minus some configurable ε. This class is meant to be called as a function after instantiation; its return is ``True`` if the numeric validator is within a set lower limit, and ``False`` otherwise. """ def __init__(self, func, epsilon=0.05): """ :param func: Numeric validator function. :param epsilon: Initial "wiggle room" that the validator allows. """ self.func = func self.bound = None self.epsilon = epsilon self.__name__ = func.__name__ def __call__(self, partition): if not self.bound: self.bound = self.func(partition) - self.epsilon return self.func(partition) >= self.bound
[docs]class WithinPercentRangeOfBounds: def __init__(self, func, percent): self.func = func self.percent = float(percent) / 100.0 self.lbound = None self.ubound = None def __call__(self, partition): if not (self.lbound and self.ubound): self.lbound = self.func(partition) * (1.0 - self.percent) self.ubound = self.func(partition) * (1.0 + self.percent) return True else: return self.lbound <= self.func(partition) <= self.ubound