Source code for selectinf.constraints.intervals

import numpy as np
import warnings
import operator

from heapq import merge

[docs]class intervals(object): r""" This class implements methods for intervals or union of two unbounded intervals, when all these sets have a point in their intersection """
[docs] def __init__(self, I = None): """ Create a intervals object, with some unbounded and bounded intervals Parameters ---------- I : tuple I is a tuple (inf, sup), the interval created Returns ------- interv : intervals The intervals object Warning : sup has to be larger than inf. If not, it raises a ValueError exception If sup == inf, it creates an empty interval, and raise a Warning >>> I = intervals() >>> I2 = intervals((-1, 1)) """ if I == None: self._U = [] else: ## Check that the interval is correct (inf, sup) = I if sup < inf: raise ValueError("The given tuple " + \ "does not represent an interval : " + repr(I)) # elif inf == sup: # self._U = [] else: self._U = [I]
def __call__(self, x): """ Check if x is in the intersection of the intervals Parameters ---------- x : float The point you want to know if it is in the intervals Returns ------- is_in : bool True if x is in the intersection, False if it's not Examples -------- >>> I = intervals() >>> I(2) False >>> I = intervals.intersection(intervals((-1, 6)), \ intervals(( 0, 7)), \ ~intervals((1, 4))) >>> x1, x2, x3, x4, x5 = 0.5, 1.5, 5, 6.5, 8 >>> I(x1), I(x2), I(x3), I(x4), I(x5) (True, False, True, False, False) """ return any( a <= x and x <= b for (a, b) in self ) def __len__(self): """ Return the number of connex intervas composing this instance >>> I = intervals.intersection(intervals((-1, 6)), \ intervals(( 0, 7)), \ ~intervals((1, 4))) >>> len(I) 2 """ return len(self._U) def __invert__(self): """ Return the complement of the interval in the reals >>> I = intervals.intersection(intervals((-1, 6)), \ intervals(( 0, 7)), \ ~intervals((1, 4))) >>> print(~I) [(-inf, 0), (1, 4), (6, inf)] """ if len(self) == 0: return intervals((-np.inf, np.inf)) inverse = intervals() a, _ = self._U[0] if a > -np.inf: inverse._U.append((-np.inf, a)) for (a1, b1), (a2, b2) in zip(self._U[:-1], self._U[1:]): inverse._U.append((b1, a2)) _, b = self._U[-1] if b < np.inf: inverse._U.append((b, np.inf)) return inverse def __repr__(self): return repr(self._U) def __iter__(self): return iter(self._U) def __getitem__(self,index): return self._U[index]
[docs] @staticmethod def union(*interv): """ Return the union of all the given intervals Parameters ---------- interv1, ... : interv intervals instance Returns ------- union, a new intervals instance, representing the union of interv1, ... >>> I = intervals.union(intervals((-np.inf, 0)), \ intervals((-1, 1)), \ intervals((3, 6))) >>> print(I) [(-inf, 1), (3, 6)] """ ## Define the union of an empty family as an empty set union = intervals() if len(interv) == 0: return interv interv_merged_gen = merge(*interv) old_a, old_b = None, None for new_a, new_b in interv_merged_gen: if old_b is not None and new_a < old_b: # check to see if union of (old_a, old_b) and # (new_a, new_b) is (old_a, new_b) old_b = max(old_b, new_b) elif old_b is None: # first interval old_a, old_b = new_a, new_b else: union._U.append((old_a, old_b)) old_a, old_b = new_a, new_b union._U.append((old_a, old_b)) return union
[docs] @staticmethod def intersection(*interv): """ Return the intersection of all the given intervals Parameters ---------- interv1, ... : interv intervals instance Returns ------- intersection, a new intervals instance, representing the intersection of interv1, ... >>> I = intervals.intersection(intervals((-1, 6)), \ intervals(( 0, 7)), \ ~intervals((1, 4))) >>> print(I) [(0, 1), (4, 6)] """ if len(interv) == 0: I = intervals() return ~I return ~(intervals.union(*(~I for I in interv)))
def __add__(self, offset): """ Add an offset to the intervals Parameters ---------- off : float The offset added Returns ------- interv : intervals a new instance, self + offset Examples -------- >>> I = intervals.intersection(intervals((-1, 6)), \ intervals(( 0, 7)), \ ~intervals((1, 4))) >>> J = I+2 >>> print(J) [(2, 3), (6, 8)] """ interv = intervals() interv._U = [(a+offset, b+offset) for (a, b) in self._U] return interv
if __name__ == "__main__": import doctest doctest.testmod()