def histogram_differences(adapters: List[int]) -> HistogramOfDeltas: """Compute the histogram of jolt differences in ``adapters``.""" histo = collections.defaultdict(lambda: 0) # type: MutableMapping[int, int] for prev, current in common.pairwise(sorted([0] + adapters + [max(adapters) + 3])): delta = current - prev histo[delta] += 1 return HistogramOfDeltas(histo)
class BinRanges(DBC): """Represent the ranges of the histogram bins.""" # fmt: off @require( lambda lower_bound, upper_bound: lower_bound < upper_bound ) @require( lambda upper_bound: not math.isnan(upper_bound) and not math.isinf(upper_bound) ) @require( lambda lower_bound: not math.isnan(lower_bound) and not math.isinf(lower_bound) ) @require( lambda lower_bound, upper_bound, bin_count: ( bin_width := (upper_bound - lower_bound) / bin_count, bin_width != 0 )[1], "Bin width not numerically zero" ) @ensure( lambda result: all( previous.end == current.start for previous, current in common.pairwise(result) ), "Bin ranges without a hole" ) @ensure( lambda bin_count, include_minus_inf, result: not (include_minus_inf ^ math.isinf(result[0].start)), "include_min_inf <=> lower bound of the first bin is -inf" ) @ensure( lambda bin_count, include_inf, result: not (include_inf ^ math.isinf(result[-1].end)), "include_inf <=> upper bound of the last bin is +inf" ) @ensure( lambda bin_count, include_inf, include_minus_inf, result: not (not include_inf and not include_minus_inf) or len(result) == bin_count, "bin_count does not refer to +/- inf bins" ) @ensure( lambda bin_count, include_inf, include_minus_inf, result: not (include_inf and not include_minus_inf) or len(result) == bin_count + 1, "bin_count does not refer to +/- inf bins" ) @ensure( lambda bin_count, include_inf, include_minus_inf, result: not (not include_inf and include_minus_inf) or len(result) == bin_count + 1, "bin_count does not refer to +/- inf bins" ) @ensure( lambda bin_count, include_inf, include_minus_inf, result: not (include_inf and include_minus_inf) or len(result) == bin_count + 2, "bin_count does not refer to +/- inf bins" ) # fmt: on def __new__( cls, bin_count: int, lower_bound: float, upper_bound: float, include_minus_inf: bool, include_inf: bool, ) -> "BinRanges": """ Construct ``bin_count`` number of histogram bins between ``lower_bound`` and ``upper_bound``. If ``include_inf``, include -∞ and +∞ in the spanned total range of histogram. """ ranges = [] # type: List[Range] if include_minus_inf: ranges.append(Range(start=-math.inf, end=lower_bound)) bin_width = (upper_bound - lower_bound) / bin_count start = lower_bound for i in range(bin_count): end = start + bin_width # We need to account for numerical imprecision with summation # so that the last bin indeed matches the exact upper bound. if i < bin_count - 1: ranges.append(Range(start=start, end=end)) else: ranges.append(Range(start=start, end=upper_bound)) start = end if include_inf: ranges.append(Range(start=upper_bound, end=math.inf)) return cast(BinRanges, ranges) @overload def __getitem__(self, index: int) -> Range: """Get the bin range at the given integer index.""" pass @overload def __getitem__(self, index: slice) -> "BinRanges": """Get the slice of the bin ranges.""" pass def __getitem__(self, index: Union[int, slice]) -> Union[Range, "BinRanges"]: """Get the bin range at the given index.""" raise NotImplementedError("Only for type annotations") def __len__(self) -> int: """Return the number of the bin ranges.""" raise NotImplementedError("Only for type annotations") def __iter__(self) -> Iterator[Range]: """Iterate over the bin ranges.""" raise NotImplementedError("Only for type annotations")
return object.__eq__(self, other) def __repr__(self) -> str: """Represent the instance as a string for debugging.""" return ( f"{self.__class__.__name__}(" f"{self.value!r}, {self.start}, {self.end}, {self.kind.value!r})") # fmt: off @ensure(lambda text, result: tokens_to_text(result) == text # type: ignore ) @ensure(lambda text, result: all(token.value == text[token.start:token.end] for token in result), "Token values correct") @ensure(lambda result: all(token1.end == token2.start for token1, token2 in common.pairwise(result)), "Tokens consecutive") @ensure( lambda text, result: not (len(result) > 0) or result[-1].end == len(text), "Text tokenized till the end") @ensure(lambda result: not (len(result) > 0) or result[0].start == 0, "Text tokenized from the start") # fmt: on def tokenize(text: str) -> List[Token]: """Tokenize the given ``text``.""" if len(text) == 0: return [] result = [] # type: List[Token] cursor = 0