Source code for pybrops.core.util.subroutines

"""
Module containing miscellaneous utility subroutines.
"""

from typing import Generator
import numpy
import math

__all__ = [
    "srange",
    "matrix_is_sorted",
    "slice_to_range",
    "slice_to_list",
    "human2bytes",
]

[docs] def srange(start: int, stop: int, step: int) -> Generator: """ Stop range generator. Similar to a normal ``range`` generator object, but also yields the stop index as its final output. Parameters ---------- start : int Starting index. stop : int Stopping index. step : int Step to advance. Yields ------ out : Generator A Generator for indices. """ yield from range(start, stop, step) yield stop
[docs] def matrix_is_sorted(mat: numpy.ndarray) -> bool: """ Determine if a matrix is sorted in ascending order. Parameters ---------- mat : numpy.ndarray Input matrix. Returns ------- out : bool ``True`` if the matrix is sorted in ascending order, otherwise ``False``. """ for i in range(mat.size-1): if mat[i] > mat[i+1]: return False return True
[docs] def slice_to_range(s: slice, end: int) -> range: """ Convert a ``slice`` object to a ``range`` object. Parameters ---------- s : slice Slice to convert. end : int End index. Returns ------- out : range A ``range`` object representing the slice. """ ifnone = lambda x, y: y if x is None else x r = range(ifnone(s.start, 0), ifnone(s.end, end), ifnone(s.step, 1)) return r
[docs] def slice_to_list(s: slice, end: int) -> list: """ Convert a ``slice`` object to a ``list`` object. Parameters ---------- s : slice Slice to convert. end : int End index. Returns ------- out : list A ``list`` object representing the slice. """ l = list(e for e in slice_to_range(s, end)) return
# define symbol conversion coefficients HUMAN2BYTES_DICT = { # for SI system 'B' : 10**0, 'byte' : 10**0, 'K' : 10**3, 'kilo' : 10**3, 'M' : 10**6, 'mega' : 10**6, 'G' : 10**9, 'giga' : 10**9, 'T' : 10**12, 'tera' : 10**12, 'P' : 10**15, 'peta' : 10**15, 'E' : 10**18, 'exa' : 10**18, 'Z' : 10**21, 'zetta': 10**21, 'Y' : 10**24, 'iotta': 10**24, # for IEC system 'Bi' : 2**0 /8, 'bit' : 2**0 /8, 'Ki' : 2**10 /8, 'kibi' : 2**10 /8, 'Mi' : 2**20 /8, 'mebi' : 2**20 /8, 'Gi' : 2**30 /8, 'gibi' : 2**30 /8, 'Ti' : 2**40 /8, 'tebi' : 2**40 /8, 'Pi' : 2**50 /8, 'pebi' : 2**50 /8, 'Ei' : 2**60 /8, 'exbi' : 2**60 /8, 'Zi' : 2**70 /8, 'zebi' : 2**70 /8, 'Yi' : 2**80 /8, 'yobi' : 2**80 /8, # if only a number string is provided, assume bytes '' : 1 }
[docs] def human2bytes(s: str) -> int: """ Convert a human readable string representing a memory size to an integer number of bytes. Parameters ---------- s : str Human readable string representing a memory size. (e.g. 10 MB) Returns ------- out : int Number of bytes that the human readable string represents. """ # strip any white space before or after s = s.strip() # make some variables sym = '' # variable to store the symbol num = 0 # variable to count index and later store the parsed number # for each character in string 's' for c in s: # if c is not a digit nor a decimal point, # then we've hit the symbol if not c.isdigit() and c != '.': break # increment index counter num += 1 # extract symbol and strip it of whitespace sym = s[num:].strip() # convert number string to floating point num = float(s[:num]) if num > 0 else 0 # if the parsed symbol is not in the list of keys, raise an error if sym not in HUMAN2BYTES_DICT.keys(): raise ValueError( "Cannot interpret string '%s':\n"\ " Negative numbers are not allowed.\n"\ " Available symbol keys:\n"\ " %s" % (s,HUMAN2BYTES_DICT.keys()) ) # return number of bytes needed rounded up return int(math.ceil(num * HUMAN2BYTES_DICT[sym]))