Source code for pyoints.assertion

# BEGIN OF LICENSE NOTE
# This file is part of Pyoints.
# Copyright (c) 2018, Sebastian Lamprecht, Trier University,
# lamprecht@uni-trier.de
#
# Pyoints is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Pyoints is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Pyoints. If not, see <https://www.gnu.org/licenses/>.
# END OF LICENSE NOTE
"""Functions to ensure the properties of frequently used data structures.
"""

import json
import numpy as np
from numbers import Number

from . import nptools

from .misc import print_rounded


[docs]def ensure_dim(value, dim=None, min_dim=2, max_dim=np.inf): """Ensure a dimension value to be in a specific range. Parameters ---------- value : int Value representing a dimension. dim, min_dim, max_dim : optional, positive int Minimum and maximum allowed dimensions. If `dim` is provided, the `check_dim` has to be exactly `dim`. If not, the `check_dim` must be in range `[min_dim, max_dim]`. Returns ------- int Dimension value with ensured properties. Raises ------ ValueError """ value = int(value) if dim is not None: if not value == dim: m = "%i dimensions required" % dim raise ValueError(m) else: if value < min_dim: m = "at least %i dimensions required" % min_dim raise ValueError(m) if value > max_dim: m = "at most %i dimensions required" % max_dim raise ValueError(m) return value
[docs]def ensure_shape(shape, dim=None, min_dim=1, max_dim=np.inf): """Ensures the properties of an array shape. Parameters ---------- shape : array_like(int, shape=(k)) Shape of `k` dimensions to validate. Returns ------- np.ndarray(int, shape=(k)) Shape with ensured properties. Raises ------ ValueError, TypeError """ if not nptools.isarray(shape): raise TypeError("'shape' needs to an array like object") shape = np.array(shape) if not nptools.isnumeric(shape, dtypes=[np.int32, np.int64]): raise ValueError("'shape' needs to have integer values") if not len(shape.shape) == 1: raise ValueError("'shape' needs to be a vector") if dim is not None: if not shape.shape[0] == dim: raise ValueError("'shape' requires a length of %i" % dim) else: if not (shape.shape[0] >= min_dim and shape.shape[0] <= max_dim): m = "length of 'shape' needs to be in range [%i, %i]" raise ValueError(m % (min_dim, max_dim)) return shape
[docs]def ensure_length(value, length=None, min_length=0, max_length=np.inf): """Ensure a length value to be in a specific range. Parameters ---------- value : int Length value to check. length,min_length,max_length : optional, positive int Minimum and maximum allowed length. If `length` is provided, `check_length` has to be exactly `length`. If not, the `check_length` must be in range `[min_length, max_length]`. Returns ------- int Length value with ensured properties. Raises ------ ValueError """ if not isinstance(value, int): raise TypeError("'check_length' needs to be an integer") if length is not None: if not value == length: m = "length %i required" % length raise ValueError(m) else: if value < min_length: m = "length of at least %i required" % min_length raise ValueError(m) if value > max_length: m = "length of at most %i required" % max_length raise ValueError(m) return value
[docs]def isnumeric(value, min_th=-np.inf, max_th=np.inf): """Checks if a value is numeric. Parameters ---------- value : Number Value to validate. min_th,max_th : optional, Number Minimum and maximum value allowed range. Returns ------- bool Indicates whether or not the value is numeric. """ return isinstance(value, Number) and value >= min_th and value <= max_th
[docs]def iscoord(coord): """Checks if a value can be associated with a coordinate. Parameters ---------- coord : array_like Value associated with a coordinate. Returns ------- bool Indicates whether or not the value is a coordinate. """ return (hasattr(coord, '__len__') and len(coord) > 0 and not hasattr(coord[0], '__len__'))
[docs]def ensure_numarray(arr, shape=None): """Ensures the properties of an numeric numpy ndarray. Parameters ---------- arr : array_like(Number) Array like numeric object. Returns ------- np.ndarray(Number) Array with guaranteed properties. Raises ------ TypeError, ValueError Examples -------- >>> print_rounded(ensure_numarray([0,1,2])) [0 1 2] >>> print_rounded(ensure_numarray((-4,-5))) [-4 -5] """ if not nptools.isarray(arr): raise TypeError("'arr' needs to an array like object") if not isinstance(arr, np.ndarray): arr = np.array(arr) if not nptools.isnumeric(arr): raise ValueError("array 'arr' needs to be numeric") if shape is not None: if not arr.shape == shape: m = "expected shape %s, got %s" % (shape, str(arr.shape)) raise ValueError(m) return arr
[docs]def ensure_numvector(v, length=None, min_length=1, max_length=np.inf): """Ensures the properties of a numeric vector. Parameters ---------- v : array_like(Number, shape=(k)) Vector of length `n`. length,min_length,max_length : optional, positive int See `ensure_length` Returns ------- v : np.ndarray(Number, shape=(n)) Vector with guaranteed properties. Examples -------- Check a valid vector. >>> v = (3, 2, 4, 4) >>> v = ensure_numvector(v) >>> print_rounded(v) [3 2 4 4] Vector of insufficient length. >>> try: ... ensure_numvector(v, length=5) ... except ValueError as e: ... print(e) length 5 required Raises ------ TypeError, ValueError """ v = ensure_numarray(v) if not len(v.shape) == 1: raise TypeError("one dimensional vector required") ensure_length(len(v), length, min_length, max_length) return v
[docs]def ensure_indices(v, min_value=0, max_value=np.inf): """Ensures an index array to be in a specific range. Parameters ---------- v : array_like(int, shape=(n)) Array of indices to check. min_value, max_value : optional, int Minimum and maximum allowed value of `v`. Returns ------- np.ndarray(int, shape=(n)) Array of indices. Raises ------ TypeError, ValueError """ v = ensure_numvector(v) if v.dtype.kind not in ('i', 'u'): raise ValueError('integer array required') if not v.max() <= max_value: m = "index %i out of range [%i, %i]" % (v.max(), min_value, max_value) raise ValueError(m) if not v.min() >= min_value: m = "index %i out of range [%i, %i]" % (v.min(), min_value, max_value) raise ValueError(m) return v
[docs]def ensure_coords(coords, by_col=False, dim=None, min_dim=2, max_dim=np.inf): """Ensures required properties of an array associated with coordinates. Parameters ---------- coords : array_like(Number, shape=(n, k)) Represents `n` data points of `k` dimensions in a Cartesian coordinate system. by_col : optional, bool Indicates whether or not the coordinates are provided column by column instead of row by row. dim,min_dim,max_dim : optional, positive int See `ensure_dim`. Returns ------- coords : np.ndarray(Number, shape=(n, k)) Coordinates with guaranteed properties. Raises ------ TypeError, ValueError Examples -------- Coordinates provided row by row. >>> coords = ensure_coords([(3, 2), (2, 4), (-1, 2), (9, 3)]) >>> print(isinstance(coords, np.ndarray)) True >>> print_rounded(coords) [[ 3 2] [ 2 4] [-1 2] [ 9 3]] Coordinates provided column by column. >>> coords = ensure_coords([(3, 2, -1, 9), (2, 4, 2, 3)], by_col=True) >>> print_rounded(coords) [[ 3 2] [ 2 4] [-1 2] [ 9 3]] See Also -------- ensure_polar """ coords = ensure_numarray(coords) if by_col: coords = coords.T if not len(coords.shape) == 2: m = "malformed shape of 'coords', got '%s'" % str(coords.shape) raise ValueError(m) ensure_dim(coords.shape[1], dim, min_dim, max_dim) return coords
[docs]def ensure_polar(pcoords, by_col=False, dim=None, min_dim=2, max_dim=np.inf): """Ensures the properties of polar coordinates. Parameters ---------- pcoords : array_like(Number, shape=(n,k)) Represents `n` data points of `k` dimensions in a polar coordinate system. by_col : optional, bool Defines whether or not the coordinates are provided column by column instead of row by row. dim,min_dim,max_dim : optional, positive int See `ensure_dim`. Raises ------ TypeError, ValueError Returns ------- pcoords : np.ndarray(Number, shape=(n,k)) Polar coordinates with guaranteed properties. See Also -------- ensure_coords """ pcoords = ensure_coords( pcoords, by_col=by_col, dim=dim, min_dim=min_dim, max_dim=max_dim ) if not np.all(pcoords[:, 0] >= 0): raise ValueError("malformed polar radii") return pcoords
[docs]def ensure_tmatrix(T, dim=None, min_dim=2, max_dim=np.inf): """Ensures the properties of transformation matrix. Parameters ---------- T : array_like(Number, shape=(k+1,k+1)) Transformation matrix. dim,min_dim,max_dim : optional, positive int See `ensure_dim`. Returns ------- T : np.matrix(Number, shape=(k+1,k+1)) Transformation matrix with guaranteed properties. Raises ------ TypeError, ValueError See Also -------- transformation.matrix """ if not nptools.isarray(T): raise ValueError("transformation matrix is not an array") if not isinstance(T, np.ndarray): T = np.asarray(T) if not nptools.isnumeric(T): raise ValueError("'T' needs to be numeric") if not len(T.shape) == 2: raise ValueError("malformed shape of transformation matrix") if not T.shape[0] == T.shape[1]: raise ValueError("transformation matrix is not a square matrix") ensure_dim(T.shape[0] - 1, dim, min_dim, max_dim) return T
[docs]def ensure_json(js): """Ensures the properties of a serializable json object. Parameters ---------- js : dict Dictionary to convert to a serializable json object. Returns ------- dict Serializable json object. """ class JsonEncoder(json.JSONEncoder): def default(self, obj): if isinstance(obj, np.recarray): return {key: obj[key].tolist() for key in obj.dtype.names} if isinstance(obj, np.ndarray): return obj.tolist() if isinstance(obj, np.int64): return int(obj) if isinstance(obj, np.float32): return float(obj) return json.JSONEncoder.default(self, obj) return json.loads(json.dumps(js, cls=JsonEncoder))