Source code for py2store.utils.affine_conversion

"""
utils to carry out affine transformations (of indices)
"""


[docs]class AffineConverter(object): """ Getting a callable that will perform an affine conversion. Note, it does it as (val - offset) * scale (Note slope-intercept style (though there is the .from_slope_and_intercept constructor method for that) Inverse is available through the inv method, performing: val / scale + offset >>> convert = AffineConverter(scale=0.5, offset=1) >>> convert(0) -0.5 >>> convert(10) 4.5 >>> convert.inv(4) 9.0 >>> convert.inv(4.5) 10.0 """ def __init__(self, scale=1.0, offset=0.0): self.scale = scale self.offset = offset @classmethod def from_slope_and_intercept(cls, slope=1.0, intercept=0.0): cls(offset=-intercept / slope, scale=slope) def __call__(self, x): return (x - self.offset) * self.scale def inv(self, x): return x / self.scale + self.offset def map(self, seq): return (self(x) for x in seq) def invmap(self, seq): return (self.inv(x) for x in seq)
[docs]def get_affine_converter_and_inverse( scale=1, offset=0, source_type_cast=None, target_type_cast=None ): """ Getting two affine functions with given scale and offset, that are inverse of each other. Namely (for input val): (val - offset) * scale and val / scale + offset Note this is not "slope intercept" style!! The source_type_cast and target_type_case (optional), allow the user to specify if these transformations need to be further cast to a given type. :param scale: :param offset: :param source_type_cast: function to apply to input :param target_type_cast: function to apply to output :return: Two single val functions: affine_converter, inverse_affine_converter Note: Code is a lot more complex than the basic operations it performs. The reason was a worry of efficiency since the functions that are returned are intended to be used in long loops. See also: ocore.utils.conversion.AffineConverter >>> affine_converter, inverse_affine_converter = get_affine_converter_and_inverse(scale=0.5,offset=1) >>> affine_converter(0) -0.5 >>> affine_converter(10) 4.5 >>> inverse_affine_converter(4) 9.0 >>> inverse_affine_converter(4.5) 10.0 >>> affine_converter, inverse_affine_converter = get_affine_converter_and_inverse(scale=0.5,offset=1,target_type_cast=int) >>> affine_converter(10) 4 """ if offset != 0: if scale != 1: if target_type_cast is None: def affine_converter(val): return (val - offset) * scale else: def affine_converter(val): return target_type_cast((val - offset) * scale) if source_type_cast is None: def inverse_affine_converter(val): return val / scale + offset else: def inverse_affine_converter(val): return source_type_cast(val / scale + offset) else: # scale 1, so can be ignored if target_type_cast is None: def affine_converter(val): return val - offset else: def affine_converter(val): return target_type_cast(val - offset) if source_type_cast is None: def inverse_affine_converter(val): return val + offset else: def inverse_affine_converter(val): return source_type_cast(val + offset) else: # no offset if target_type_cast is None: def affine_converter(val): return scale * val else: def affine_converter(val): return target_type_cast(scale * val) if source_type_cast is None: def inverse_affine_converter(val): return val / scale else: def inverse_affine_converter(val): return source_type_cast(val / scale) return affine_converter, inverse_affine_converter