Source code for colour.continuous.abstract

# -*- coding: utf-8 -*-
"""
Abstract Continuous Function
============================

Defines the abstract class implementing support for abstract continuous
function:

-   :class:`colour.continuous.AbstractContinuousFunction`.
"""

from __future__ import division, unicode_literals

import numpy as np
from abc import ABCMeta, abstractmethod, abstractproperty
from copy import deepcopy

# Python 3 compatibility.
try:
    from operator import div, idiv
except ImportError:
    from operator import truediv, itruediv

    div = truediv
    idiv = itruediv
from six import add_metaclass

from colour.utilities import as_float, closest, is_uniform, is_string

__author__ = 'Colour Developers'
__copyright__ = 'Copyright (C) 2013-2020 - Colour Developers'
__license__ = 'New BSD License - https://opensource.org/licenses/BSD-3-Clause'
__maintainer__ = 'Colour Developers'
__email__ = 'colour-developers@colour-science.org'
__status__ = 'Production'

__all__ = ['AbstractContinuousFunction']


[docs]@add_metaclass(ABCMeta) class AbstractContinuousFunction: """ Defines the base class for abstract continuous function. This is an :class:`ABCMeta` abstract class that must be inherited by sub-classes. The sub-classes are expected to implement the :meth:`colour.continuous.AbstractContinuousFunction.function` method so that evaluating the function for any independent domain :math:`x \\in\\mathbb{R}` variable returns a corresponding range :math:`y \\in\\mathbb{R}` variable. A conventional implementation adopts an interpolating function encapsulated inside an extrapolating function. The resulting function independent domain, stored as discrete values in the :attr:`colour.continuous.AbstractContinuousFunction.domain` attribute corresponds with the function dependent and already known range stored in the :attr:`colour.continuous.AbstractContinuousFunction.range` attribute. Parameters ---------- name : unicode, optional Continuous function name. Attributes ---------- name domain range interpolator interpolator_kwargs extrapolator extrapolator_kwargs function Methods ------- __str__ __repr__ __hash__ __getitem__ __setitem__ __contains__ __len__ __eq__ __ne__ __iadd__ __add__ __isub__ __sub__ __imul__ __mul__ __idiv__ __div__ __ipow__ __pow__ arithmetical_operation fill_nan domain_distance is_uniform copy """ def __init__(self, name=None): self._name = '{0} ({1})'.format(self.__class__.__name__, id(self)) self.name = name @property def name(self): """ Getter and setter property for the abstract continuous function name. Parameters ---------- value : unicode Value to set the abstract continuous function name with. Returns ------- unicode Abstract continuous function name. """ return self._name @name.setter def name(self, value): """ Setter for **self.name** property. """ if value is not None: assert is_string(value), ( ('"{0}" attribute: "{1}" type is not "str" or "unicode"!' ).format('name', value)) self._name = value def _get_dtype(self): """ Getter and setter property for the abstract continuous function dtype, must be reimplemented by sub-classes. Parameters ---------- value : type Value to set the abstract continuous function dtype with. Returns ------- type Abstract continuous function dtype. """ pass def _set_dtype(self, value): """ Setter for **self.dtype** property, must be reimplemented by sub-classes. """ pass domain = abstractproperty(_get_dtype, _set_dtype) def _get_domain(self): """ Getter and setter property for the abstract continuous function independent domain :math:`x` variable, must be reimplemented by sub-classes. Parameters ---------- value : array_like Value to set the abstract continuous function independent domain :math:`x` variable with. Returns ------- ndarray Abstract continuous function independent domain :math:`x` variable. """ pass def _set_domain(self, value): """ Setter for the **self.domain** property, must be reimplemented by sub-classes. """ pass domain = abstractproperty(_get_domain, _set_domain) def _get_range(self): """ Getter and setter property for the abstract continuous function corresponding range :math:`y` variable, must be reimplemented by sub-classes. Parameters ---------- value : array_like Value to set the abstract continuous function corresponding range :math:`y` variable with. Returns ------- ndarray Abstract continuous function corresponding range :math:`y` variable. """ pass def _set_range(self, value): """ Setter for the **self.range** property, must be reimplemented by sub-classes. """ pass range = abstractproperty(_get_range, _set_range) def _get_interpolator(self): """ Getter and setter property for the abstract continuous function interpolator type, must be reimplemented by sub-classes. Parameters ---------- value : type Value to set the abstract continuous function interpolator type with. Returns ------- type Abstract continuous function interpolator type. """ pass def _set_interpolator(self, value): """ Setter for the **self.interpolator** property, must be reimplemented by sub-classes. """ pass interpolator = abstractproperty(_get_interpolator, _set_interpolator) def _get_interpolator_kwargs(self): """ Getter and setter property for the abstract continuous function interpolator instantiation time arguments, must be reimplemented by sub-classes. Parameters ---------- value : dict Value to set the abstract continuous function interpolator instantiation time arguments to. Returns ------- dict Abstract continuous function interpolator instantiation time arguments. """ pass def _set_interpolator_kwargs(self, value): """ Setter for the **self.interpolator_kwargs** property, must be reimplemented by sub-classes. """ pass interpolator_kwargs = abstractproperty(_get_interpolator_kwargs, _set_interpolator_kwargs) def _get_extrapolator(self): """ Getter and setter property for the abstract continuous function extrapolator type, must be reimplemented by sub-classes. Parameters ---------- value : type Value to set the abstract continuous function extrapolator type with. Returns ------- type Abstract continuous function extrapolator type. """ pass def _set_extrapolator(self, value): """ Setter for the **self.extrapolator** property, must be reimplemented by sub-classes. """ pass extrapolator = abstractproperty(_get_extrapolator, _set_extrapolator) def _get_extrapolator_kwargs(self): """ Getter and setter property for the abstract continuous function extrapolator instantiation time arguments, must be reimplemented by sub-classes. Parameters ---------- value : dict Value to set the abstract continuous function extrapolator instantiation time arguments to. Returns ------- dict Abstract continuous function extrapolator instantiation time arguments. """ pass def _set_extrapolator_kwargs(self, value): """ Setter for the **self.extrapolator_kwargs** property, must be reimplemented by sub-classes. """ pass extrapolator_kwargs = abstractproperty(_get_extrapolator_kwargs, _set_extrapolator_kwargs) def _get_function(self): """ Getter and setter property for the abstract continuous function callable, must be reimplemented by sub-classes. Parameters ---------- value : object Attribute value. Returns ------- callable Abstract continuous function callable. Notes ----- - This property is read only. """ pass def _set_function(self, value): """ Setter for the **self.function** property, must be reimplemented by sub-classes. """ pass function = abstractproperty(_get_function, _set_function)
[docs] @abstractmethod def __str__(self): """ Returns a formatted string representation of the abstract continuous function, must be reimplemented by sub-classes. Returns ------- unicode Formatted string representation. """ return '<{0} object at {1}>'.format(self.__class__.__name__, id(self))
[docs] @abstractmethod def __repr__(self): """ Returns an evaluable string representation of the abstract continuous function, must be reimplemented by sub-classes. Returns ------- unicode Evaluable string representation. """ return '{0}()'.format(self.__class__.__name__)
[docs] @abstractmethod def __hash__(self): """ Returns the abstract continuous function hash. Returns ------- int Object hash. """ pass
[docs] @abstractmethod def __getitem__(self, x): """ Returns the corresponding range :math:`y` variable for independent domain :math:`x` variable, must be reimplemented by sub-classes. Parameters ---------- x : numeric, array_like or slice Independent domain :math:`x` variable. Returns ------- numeric or ndarray math:`y` range value. """ pass
[docs] @abstractmethod def __setitem__(self, x, y): """ Sets the corresponding range :math:`y` variable for independent domain :math:`x` variable, must be reimplemented by sub-classes. Parameters ---------- x : numeric, array_like or slice Independent domain :math:`x` variable. y : numeric or ndarray Corresponding range :math:`y` variable. """ pass
[docs] @abstractmethod def __contains__(self, x): """ Returns whether the abstract continuous function contains given independent domain :math:`x` variable, must be reimplemented by sub-classes. Parameters ---------- x : numeric, array_like or slice Independent domain :math:`x` variable. Returns ------- bool Is :math:`x` domain value contained. """ pass
[docs] def __len__(self): """ Returns the abstract continuous function independent domain :math:`x` variable elements count. Returns ------- int Independent domain :math:`x` variable elements count. """ return len(self.domain)
[docs] @abstractmethod def __eq__(self, other): """ Returns whether the abstract continuous function is equal to given other object, must be reimplemented by sub-classes. Parameters ---------- other : object Object to test whether it is equal to the abstract continuous function. Returns ------- bool Is given object equal to the abstract continuous function. """ pass
[docs] @abstractmethod def __ne__(self, other): """ Returns whether the abstract continuous function is not equal to given other object, must be reimplemented by sub-classes. Parameters ---------- other : object Object to test whether it is not equal to the abstract continuous function. Returns ------- bool Is given object not equal to the abstract continuous function. """ pass
[docs] def __add__(self, a): """ Implements support for addition. Parameters ---------- a : numeric or array_like or AbstractContinuousFunction :math:`a` variable to add. Returns ------- AbstractContinuousFunction Variable added abstract continuous function. """ return self.arithmetical_operation(a, '+')
[docs] def __iadd__(self, a): """ Implements support for in-place addition. Parameters ---------- a : numeric or array_like or AbstractContinuousFunction :math:`a` variable to add in-place. Returns ------- AbstractContinuousFunction In-place variable added abstract continuous function. """ return self.arithmetical_operation(a, '+', True)
[docs] def __sub__(self, a): """ Implements support for subtraction. Parameters ---------- a : numeric or array_like or AbstractContinuousFunction :math:`a` variable to subtract. Returns ------- AbstractContinuousFunction Variable subtracted abstract continuous function. """ return self.arithmetical_operation(a, '-')
[docs] def __isub__(self, a): """ Implements support for in-place subtraction. Parameters ---------- a : numeric or array_like or AbstractContinuousFunction :math:`a` variable to subtract in-place. Returns ------- AbstractContinuousFunction In-place variable subtracted abstract continuous function. """ return self.arithmetical_operation(a, '-', True)
[docs] def __mul__(self, a): """ Implements support for multiplication. Parameters ---------- a : numeric or array_like or AbstractContinuousFunction :math:`a` variable to multiply by. Returns ------- AbstractContinuousFunction Variable multiplied abstract continuous function. """ return self.arithmetical_operation(a, '*')
[docs] def __imul__(self, a): """ Implements support for in-place multiplication. Parameters ---------- a : numeric or array_like or AbstractContinuousFunction :math:`a` variable to multiply by in-place. Returns ------- AbstractContinuousFunction In-place variable multiplied abstract continuous function. """ return self.arithmetical_operation(a, '*', True)
[docs] def __div__(self, a): """ Implements support for division. Parameters ---------- a : numeric or array_like or AbstractContinuousFunction :math:`a` variable to divide by. Returns ------- AbstractContinuousFunction Variable divided abstract continuous function. """ return self.arithmetical_operation(a, '/')
[docs] def __idiv__(self, a): """ Implements support for in-place division. Parameters ---------- a : numeric or array_like or AbstractContinuousFunction :math:`a` variable to divide by in-place. Returns ------- AbstractContinuousFunction In-place variable divided abstract continuous function. """ return self.arithmetical_operation(a, '/', True)
__itruediv__ = __idiv__ __truediv__ = __div__
[docs] def __pow__(self, a): """ Implements support for exponentiation. Parameters ---------- a : numeric or array_like or AbstractContinuousFunction :math:`a` variable to exponentiate by. Returns ------- AbstractContinuousFunction Variable exponentiated abstract continuous function. """ return self.arithmetical_operation(a, '**')
[docs] def __ipow__(self, a): """ Implements support for in-place exponentiation. Parameters ---------- a : numeric or array_like or AbstractContinuousFunction :math:`a` variable to exponentiate by in-place. Returns ------- AbstractContinuousFunction In-place variable exponentiated abstract continuous function. """ return self.arithmetical_operation(a, '**', True)
[docs] @abstractmethod def arithmetical_operation(self, a, operation, in_place=False): """ Performs given arithmetical operation with :math:`a` operand, the operation can be either performed on a copy or in-place, must be reimplemented by sub-classes. Parameters ---------- a : numeric or ndarray or AbstractContinuousFunction Operand. operation : object Operation to perform. in_place : bool, optional Operation happens in place. Returns ------- AbstractContinuousFunction Abstract continuous function. """ pass
[docs] @abstractmethod def fill_nan(self, method='Interpolation', default=0): """ Fill NaNs in independent domain :math:`x` variable and corresponding range :math:`y` variable using given method, must be reimplemented by sub-classes. Parameters ---------- method : unicode, optional **{'Interpolation', 'Constant'}**, *Interpolation* method linearly interpolates through the NaNs, *Constant* method replaces NaNs with ``default``. default : numeric, optional Value to use with the *Constant* method. Returns ------- AbstractContinuousFunction NaNs filled abstract continuous function. """ pass
[docs] def domain_distance(self, a): """ Returns the euclidean distance between given array and independent domain :math:`x` closest element. Parameters ---------- a : numeric or array_like :math:`a` variable to compute the euclidean distance with independent domain :math:`x` variable. Returns ------- numeric or array_like Euclidean distance between independent domain :math:`x` variable and given :math:`a` variable. """ n = closest(self.domain, a) return as_float(np.abs(a - n))
[docs] def is_uniform(self): """ Returns if independent domain :math:`x` variable is uniform. Returns ------- bool Is independent domain :math:`x` variable uniform. """ return is_uniform(self.domain)
[docs] def copy(self): """ Returns a copy of the sub-class instance. Returns ------- AbstractContinuousFunction Abstract continuous function copy. """ return deepcopy(self)