# Copyright 2021 D-Wave Systems Inc.
#
#    Licensed under the Apache License, Version 2.0 (the "License");
#    you may not use this file except in compliance with the License.
#    You may obtain a copy of the License at
#
#        http://www.apache.org/licenses/LICENSE-2.0
#
#    Unless required by applicable law or agreed to in writing, software
#    distributed under the License is distributed on an "AS IS" BASIS,
#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#    See the License for the specific language governing permissions and
#    limitations under the License.

r"""This module contains a class that represents an influence path/functional.
"""

#####################################
## Load libraries/packages/modules ##
#####################################

# For explicitly releasing memory.
import gc

# For general array handling.
import numpy as np

# For creating tensor networks.
import tensornetwork as tn

# Assign an alias to the ``spinbosonchain`` library.
import spinbosonchain as sbc

# For calculating the total two-point influence function.
import spinbosonchain._influence.twopt

# For creating influence nodes and MPOs used to calculate the influence path.
import spinbosonchain._influence.tensorfactory

# For applying MPO's to MPS's.
import spinbosonchain._mpomps

# For shifting orthogonal centers of MPS's.
import spinbosonchain._qr

############################
## Authorship information ##
############################

__author__     = "D-Wave Systems Inc."
__copyright__  = "Copyright 2021"
__credits__    = ["Matthew Fitzpatrick"]
__maintainer__ = "D-Wave Systems Inc."
__email__      = "support@dwavesys.com"
__status__     = "Development"

##################################
## Define classes and functions ##
##################################

class PathPklPart():
    def __init__(self, compress_params, alg):
        # DM: Detailed manuscript.

        # 'Pickle parts' can be saved to file in case of a crash and then
        # subsequently recovered in a future run. See docs of method
        # spinbosonchain.state.recover_and_resume for background information on
        # pickles and simulation recovery.

        self.compress_params = compress_params
        self.alg = alg  # yz- or z-noise algorithm?

        self.n = 0  # Time step index.
        self.m2 = 0

        # For caching purposes.
        self.Xi_I_dashv_1_nodes = None  # Introduced in Eq. (143) of DM.
        self.Xi_I_dashv_2_nodes = None  # Introduced in Eq. (143) of DM.
        self.Xi_I_dashv_nodes = None  # Introduced in Eq. (143) of DM.
        self.Xi_I_1_1_nodes = None  # Introduced in Eq. (126) of DM.
        self.Xi_I_1_2_nodes = None  # Introduced in Eq. (126) of DM.

        return None

class Path():
    r"""This class represents a local influence path/functional, given by
    Eq. (103) of the detailed manuscript (DM). For context read Sec. 4.3 and 4.4
    of DM."""
    def __init__(self,
                 r,  # Site index.
                 system_model,
                 bath_model,
                 dt,  # Time step size.
                 compress_params,
                 pkl_parts=None):  # Used in loading/creating backups.
        # DM: Detailed manuscript.

        # 'Pickle parts' can be saved to file in case of a crash and then
        # subsequently recovered in a future run. See docs of method
        # spinbosonchain.state.recover_and_resume for background information on
        # pickles and simulation recovery.

        # total_two_point_influence represents the quantity in Eq. (109) of DM.
        total_two_point_influence = sbc._influence.twopt.Total(r,
                                                               system_model,
                                                               bath_model,
                                                               dt,
                                                               pkl_parts)

        # This class generates the M-nodes given by Eq. (118) of DM.
        InfluenceNodeRank3 = sbc._influence.tensorfactory.InfluenceNodeRank3

        # This class generates the W-nodes given by Eqs. (120)-(123) of DM.
        InfluenceMPO = sbc._influence.tensorfactory.InfluenceMPO

        influence_node_rank_3_factory = \
            InfluenceNodeRank3(total_two_point_influence)
        self.influence_mpo_factory = \
            InfluenceMPO(total_two_point_influence)

        # K_tau is given by Eq. (87) of DM.
        K_tau = total_two_point_influence.z_bath.pkl_part.K_tau

        # dm is given by Eq. (89) of DM.
        dm = 3 if bath_model.y_spectral_densities is not None else 1

        # mu_m_tau is given by Eq. (108) of DM.
        self.mu_m_tau = lambda m: max(0, m-K_tau*dm+1)

        # The 'first iteration procedure' involves executing Eqs. (130)-(137) of
        # DM, whereas the 'second iteration procedure' involves executing
        # Eqs. (146)-(154) of DM.
        self.max_m2_in_first_iteration_procedure = lambda n: n*dm-2
        self.max_m2_in_second_iteration_procedure = lambda n: (n+1)*dm-1

        if pkl_parts is None:  # Create pickle part from scratch.
            alg = total_two_point_influence.alg  # yz- or z-noise algorithm.
            self.pkl_part = PathPklPart(compress_params, alg)

            # M_r_1_0_I is given by Eq. (118) of DM with m2=0 and n=1.
            M_r_1_0_I = influence_node_rank_3_factory.build(m=0, n=1)

            # The quantities below are introduced in Eq. (126) of DM.
            self.pkl_part.Xi_I_1_1_nodes = []
            self.pkl_part.Xi_I_1_2_nodes = [M_r_1_0_I]
        else:  # Reload pickle part from backup.
            self.pkl_part = pkl_parts["influence_path"]

        return None

    def reset_evolve_procedure(self, num_n_steps, k, forced_gc):
        # DM: Detailed manuscript.

        # The 'evolve procedure' refers to the step-evolution procedure
        # implemented for the spinbosonchain.state.SystemState class, which
        # represents the system state. An 'evolution step' consists of a
        # sequence of 'k-steps', where in each k-step, a MPO is constructed
        # which is applied to the MPS representing the system state [given by
        # one of Eqs. (215)-(217) of DM depending on scenario]. Each of these
        # MPO's requires a set of influence nodes taken from the MPS's
        # representing the local influence paths. Details on the MPO
        # construction procedure are given in Sec. 4.8 of DM. Instances of
        # k-steps are given by Eqs. (219), (220), (221), (223), and (224) of
        # DM. The current method here essentially calculates the required set of
        # influence nodes to perform the first k-step of the current evolution
        # step.

        # The 'first iteration procedure' involves executing Eqs. (130)-(137) of
        # DM, whereas the 'second iteration procedure' involves executing
        # Eqs. (146)-(154) of DM.
        n = self.pkl_part.n
        m2 = max(0, self.max_m2_in_first_iteration_procedure(n)+1)
        n += num_n_steps

        self.pkl_part.n = n
        self.pkl_part.m2 = m2

        while self.first_m2_step_seq_in_reset_evolve_procedure_not_finished(k):
            self.m2_step()
            if forced_gc:
                gc.collect()  # Enforce garbage collection.

        if self.pkl_part.m2 <= self.max_m2_in_first_iteration_procedure(n):
            return None

        # At this point the first iteration procedure as finished, so the
        # second procedure is initiated. The following code block is essentially
        # Eq. (146) of DM.
        self.pkl_part.Xi_I_dashv_1_nodes = []
        self.pkl_part.Xi_I_dashv_2_nodes = self.pkl_part.Xi_I_1_2_nodes[:]

        while self.second_m2_step_seq_in_reset_evolve_procedure_not_finished(k):
            self.m2_step()
            if forced_gc:
                gc.collect()  # Enforce garbage collection.

        return None

    def first_m2_step_seq_in_reset_evolve_procedure_not_finished(self, k):
        # See comments in method reset_evolve_procedure for context.

        m2_limit = self.max_m2_in_first_iteration_procedure(self.pkl_part.n)

        if (k != -1) and (self.pkl_part.alg == "yz-noise"):
            target_num_Xi_I_1_1_nodes = 3
        else:
            target_num_Xi_I_1_1_nodes = 1

        num_Xi_I_1_1_nodes = len(self.pkl_part.Xi_I_1_1_nodes)

        # If target_num_Xi_I_1_1_nodes of the Xi_I_1_1 nodes have been obtained
        # before iterating through all the m2 steps of the 'first procedure',
        # then the 'reset evolve procedure' is finished and we can proceed to
        # executing our first 'k-step'. Otherwise, we iterate through all the m2
        # steps of the first procedure.

        condition_1 = self.pkl_part.m2 <= m2_limit
        condition_2 = num_Xi_I_1_1_nodes < target_num_Xi_I_1_1_nodes

        return condition_1 and condition_2

    def second_m2_step_seq_in_reset_evolve_procedure_not_finished(self, k):
        # See comments in method reset_evolve_procedure for context.

        m2_limit = self.max_m2_in_second_iteration_procedure(self.pkl_part.n)

        if (k != -1) and (self.pkl_part.alg == "yz-noise"):
            target_num_Xi_I_dashv_1_nodes = 3
        else:
            target_num_Xi_I_dashv_1_nodes = 1

        num_Xi_I_dashv_1_nodes = len(self.pkl_part.Xi_I_dashv_1_nodes)

        # If target_num_Xi_I_dashv_1_nodes of the Xi_I_1_1 nodes have been
        # obtained before iterating through all the m2 steps of the 'second
        # procedure', then the 'reset evolve procedure' is finished and we can
        # proceed to executing our first 'k-step'. Otherwise, we iterate through
        # all the m2 steps of the secon procedure.

        condition_1 = self.pkl_part.m2 <= m2_limit
        condition_2 = num_Xi_I_dashv_1_nodes < target_num_Xi_I_dashv_1_nodes

        return condition_1 and condition_2

    def k_step(self, forced_gc):
        # DM: Detailed manuscript.

        # An 'evolution step', wherein the system state is evolved, consists of
        # a sequence of 'k-steps', where in each k-step, a MPO is constructed
        # which is applied to the MPS representing the system state [given by
        # one of Eqs. (215)-(217) of DM depending on scenario]. The role that
        # the influence paths play in a single k-step is that they construct the
        # set of influence nodes taken from the MPS's representing the local
        # influence paths that are required to construct the aforementioned MPO
        # for that k-step. Details on the MPO construction procedure are given
        # in Sec. 4.8 of DM. Instances of k-steps are given by Eqs. (219),
        # (220), (221), (223), and (224) of DM.

        # The 'first iteration procedure' involves executing Eqs. (130)-(137) of
        # DM, whereas the 'second iteration procedure' involves executing
        # Eqs. (146)-(154) of DM.
        n = self.pkl_part.n
        max_m2_in_first_iteration_procedure_plus_1 = \
            self.max_m2_in_first_iteration_procedure(n)+1
        max_m2_in_second_iteration_procedure = \
            self.max_m2_in_second_iteration_procedure(n)

        if ((self.pkl_part.alg == "z-noise")
            or (self.pkl_part.m2 == max_m2_in_second_iteration_procedure)):
            num_m2_steps = 1  # The number of m2-steps taken in current k-step.
        else:
            num_m2_steps = 3  # The number of m2-steps taken in current k-step.

        for _ in range(num_m2_steps):
            self.m2_step()
            if self.pkl_part.m2 == max_m2_in_first_iteration_procedure_plus_1:
                # The following code block is essentially Eq. (146) of DM.
                self.pkl_part.Xi_I_dashv_1_nodes = []
                self.pkl_part.Xi_I_dashv_2_nodes = \
                    self.pkl_part.Xi_I_1_2_nodes[:]
            if forced_gc:
                gc.collect()  # Enforce garbage collection.

        return None

    def m2_step(self):
        # DM: Detailed manuscript.

        # This method either performs a single 'm2-step' in the 'first
        # procedure' which involves executing Eqs. (130)-(137) of DM, or the
        # 'second procedure' which involves executing Eqs. (146)-(154) of DM.

        m2 = self.pkl_part.m2
        n = self.pkl_part.n

        if m2 <= self.max_m2_in_first_iteration_procedure(n):
            mps_nodes = self.pkl_part.Xi_I_1_2_nodes
        else:
            mps_nodes = self.pkl_part.Xi_I_dashv_2_nodes

        # The following code block implements Eq. (131) if in first procedure,
        # and Eq. (147) if in second procedure.
        node = tn.Node(np.ones([1, 4, 1]))
        mps_nodes.append(node)
        kwargs = {"nodes": mps_nodes,
                  "current_orthogonal_center_idx": len(mps_nodes) - 2}
        sbc._qr.shift_orthogonal_center_to_the_right(**kwargs)
        mps_nodes[-1] /= tn.norm(mps_nodes[-1])

        # Perform MPS compression for computational efficiency.
        kwargs = {"mpo_nodes": self.influence_mpo_factory.build(m2+1, n),
                  "mps_nodes": mps_nodes,
                  "compress_params": self.pkl_part.compress_params}
        sbc._mpomps.apply_finite_mpo_to_finite_mps_and_compress(**kwargs)

        if m2 <= self.max_m2_in_first_iteration_procedure(n):
            if self.mu_m_tau(m=m2+2) >= 1:
                # This is essentially Eq. (137) of DM.
                self.pkl_part.Xi_I_1_1_nodes.append(mps_nodes.pop(0))
            # This is essentially Eq. (136) of DM.
            self.pkl_part.Xi_I_1_2_nodes = mps_nodes
        else:
            if self.mu_m_tau(m=m2+2) >= 1:
                # This is essentially Eq. (154) of DM.
                self.pkl_part.Xi_I_dashv_1_nodes.append(mps_nodes.pop(0))
            # This is essentially Eq. (153) of DM.
            self.pkl_part.Xi_I_dashv_2_nodes = mps_nodes
            # This is essentially Eq. (156) of DM.
            self.pkl_part.Xi_I_dashv_nodes = \
                (self.pkl_part.Xi_I_dashv_1_nodes
                 + self.pkl_part.Xi_I_dashv_2_nodes)

        self.pkl_part.m2 += 1

        return None


#! /usr/bin/env python
#

""" Loading, transforming and comparing the corners of Camera CCDs."""

import numpy as np
from shapely import geometry
from shapely import affinity
from shapely.ops import cascaded_union
from descartes import PolygonPatch

##############################
#                            #
#  Camera Class              #
#                            #
##############################

class Camera:
    """
    Class for collection and manipulation of a camera's CCD corner
    coordinates. A list of CCD corner coordinates is inputted as a
    *coordsList*, resulting in a shapely.geometry.multipolygon object
    stored in *poly*. This *poly* can be geometrically translated and
    rotated to model astronomical dither patterns.

    Attributes:
        coordsList : *list*
            List of coordinates of the corners of each CCD in the camera.
            The *coordsList* must follow these rules:

            1) Coordinates are (ra, dec) numeric pairs of the angular
               position of each camera's corners.
            2) The *coordsList* must contain at least one CCD. If there
               is only one CCD in the *coordsList*, then it must be passed
               to the Camera as a list of length 1.
            2) Each CCD in the *coordsList* must contain at least three
               corners.
            4) The CCDs in the *coordsList* CANNOT overlap.
        name : *str*, optional
            Name by which to identify a Camera.

    Examples:
        1) For a *coordsList* of two CCDs:
            coordsList = [ [(0,0),(0,1),(1,1),(1,0)],
                        [(2,2),(2,3),(3,3),(3,2)] ]
            camera = Camera(coordsList)

        2) For a *coordsList* of one CCD.
            coordsList = [ [(0,0),(0,1),(1,1),(1,0)] ]
            camera = Camera(coordsList)
    """

    def __init__(self, coordsList, name=None):

        if not isinstance(coordsList[0], list):
            raise TypeError('coordsList must be a list of coordinates '
                            'for the corners of each CCD in the camera.')

        if name is not None and not isinstance(name, str):
            raise TypeError('Camera name must be a string.')

        # Combine corners of the CCDs in the coordsList into one poly
        polys = []
        for coords in coordsList:
            polys.append(geometry.Polygon(coords))
        self.poly = cascaded_union(polys)
        self.name = name

    @property
    def poly(self):
        return self.Poly

    @poly.setter
    def poly(self, newPoly):
        """
        Sets the new poly and updates the Camera's coordsList

        Parameters:
            newPoly : *shapely.geometry.multipolygon.MultiPolygon*
                       or
                       *shapely.geometry.multipolygon.Polygon*
                Sets the polygon for this Camera as *newPoly*, as well
                as updating the *coordsList*.
        """
        self.Poly = newPoly
        self.coordsList = self.get_coordsList()

    def get_coordsList(self):
        """
        Returns the *coordsList* for THIS Camera's *poly*. This list will
        follow the conventions for a *coordsList* as outlined in the
        Camera Attributes.
        """
        return self._get_coordsList(self.poly)

    def _get_coordsList(self, poly):
        """
        Returns the *coordsList* for ANY Camera's *poly*. This list will
        follow the conventions for a *coordsList* as outlined in the
        Camera Attributes.

        Parameters:
            poly : *shapely.geometry.multipolygon.MultiPolygon*
                   or
                   *shapely.geometry.multipolygon.Polygon*
                Polygon from which a *coordsList* will be calculated.
        """
        if poly.area == 0:
            # If Camera is an empty polygon
            coordsList = [[(0, 0), (0, 0), (0, 0)]]

        elif poly.type == 'MultiPolygon':
            # If Cameara is a collection of multiple polygons
            coordsList = []
            for p in poly:
                coords = []
                for x, y in p.exterior.coords:
                    coords.append((x, y))
                coordsList.append(coords)

        elif poly.type == 'Polygon':
            # If Camera is a single polygon
            coords = []
            for x, y in poly.exterior.coords:
                coords.append((x, y))
            coordsList = [coords]

        return coordsList

    def copy(self):
        """
        Returns a copy of the current Camera.
        """
        return Camera(self.coordsList)

    def buffer(self, buffer, resolution=16):
        """
        Expands the coundaries of each polygon in the Camera's *poly*
        by the size of the *buffer*.
        Parameters:
            buffer : *float*
                The number of degrees by which each polygon in *poly*
                will be expanded.
            resolution : *int*
                The number of points added to the camera *poly* to
                approximate the additional buffer
        """
        self.poly = self.poly.buffer(buffer, resolution)

    def expand_ra(self):
        """
        Applys a spherical distortion to the Camera's coordinates to
        adjust for the declination of the Camera's current position.
        This function must be called AFTER geometric transformations
        (translate, rotate) have been applied.
        """
        centroid = self.get_center()
        polys = []
        for coords in self.coordsList:
            new_coords = []
            for (coordX, coordY) in coords:
                coordX -= centroid[0]
                coordX /= np.cos(np.radians(coordY))
                coordX += centroid[0]
                new_coords.append((coordX, coordY))
            polys.append(geometry.Polygon(new_coords))
        self.poly = cascaded_union(polys)

    def collapse_ra(self):
        """
        Applys a spherical distortion to the Camera's coordinates to
        adjust for the declination of the Camera's current position.
        This function must be called BEFORE geometric transformations
        (translate, rotate) have been applied.
        """
        centroid = self.get_center()
        polys = []
        for coords in self.coordsList:
            new_coords = []
            for (coordX, coordY) in coords:
                coordX -= centroid[0]
                coordX *= np.cos(np.radians(coordY))
                coordX += centroid[0]
                new_coords.append((coordX, coordY))
            polys.append(geometry.Polygon(new_coords))
        self.poly = cascaded_union(polys)

    def rotate(self, degrees=0, origin=False):
        """
        Rotates the Camera's *poly* by *degrees*. This is a rotation
        around each polygon's center, not the origin (0,0). Rotation
        can be performed around the origin by setting the *origin* flag to
        True. Prior to and after rotation, *poly* is adjusted to account
        for spherical distrotion effects at different declinations.

        Parameters:
            degrees : *float*
                The number of degrees by which to rotate *poly*. Positive
                angles are counter-clockwise and negative are clockwise
                rotations.
            origin : *bool*
                Rotates the Camera's *poly* around the center of the *poly*
                bounding box. If set to False, rotation will be performed
                around the origin.
        """
        self.collapse_ra()
        if not origin:
            self.poly = affinity.rotate(self.poly, degrees)
        else:
            self.poly = affinity.rotate(self.poly, degrees, origin=(0, 0))
        self.expand_ra()

    def translate(self, raOffset=0, decOffset=0):
        """
        Translates the Camera's *poly* by *raOffset* and *decOffset*.
        Prior to and after rotation, the Camera's *poly* is adjusted
        to account for spherical  distrotion effects at different
        declinations.

        Parameters:
            raOffset : *float*
                The number of degrees by which to translate *poly* in
                right ascension.
            decOffset : *float*
                The number of degrees by which to translate *poly* in
                declination.
        """
        self.collapse_ra()
        self.poly = affinity.translate(self.poly,
                                       xoff=raOffset,
                                       yoff=decOffset)
        self.expand_ra()

    def get_radius(self):
        """
        Returns the radius of the smallest circle which could encompass
        all of the polygons in the Camera's *poly*. If the Camera's *poly*
        is centered around (0,0), the radius is equal to the distance to
        the polygon corner furthest from the Camera's center. Radius is
        returned in degrees.
        """
        center = self.get_center()
        radius_list = []
        for coords in self.coordsList:
            for coord in coords:
                radius = np.sqrt((coord[0] - center[0]) ** 2. +
                                 (coord[1] - center[1]) ** 2.)
                radius_list.append(radius)
        return np.max(radius_list)

    def get_area(self):
        """
        Returns the total area of all polygons in the Camera's *poly*.
        Area is returned in square degrees.
        """
        return self.poly.area

    def get_limits(self):
        """
        Returns the coordinates of the smallest box which could surround
        all of the polygons in the Camera's *poly*. Limits are returned
        in degrees.

        Returns:
            ra_lim, dec_lim : *tuple* of *floats*
                Two tuples, each containing the range of the Camera's *poly*
                in right ascension and declination respectively.
        """
        if self.poly.type == 'Polygon':
            # If Camera is a single polygon
            xArr = []
            yArr = []
            for x, y in self.poly.exterior.coords:
                xArr.append(x)
                yArr.append(y)
        else:
            # If Camera is a collection of multiple polygons
            xArr = []
            yArr = []
            for poly in self.poly:
                for x, y in poly.exterior.coords:
                    xArr.append(x)
                    yArr.append(y)

        ra_lim = (min(xArr), max(xArr))
        dec_lim = (min(yArr), max(yArr))

        return ra_lim, dec_lim

    def get_center(self, raOffset=0, decOffset=0):
        """
        Returns the geometric center of the smallest box which could
        surround all of the polygons in the Camera's *poly*. The center
        is returned in degrees. User can apply a forced offset to the
        right ascension or declination of the center if there is a known
        asymmetry in the Camera's design.

        Parameters:
            raOffset : *float*
                The number of degrees by which to offset the *poly* center
                in right ascension.
            decOffset : *float*
                The number of degrees by which to offset the *poly* center
                in declination.

        Returns:
            centerRa, centerDec : *float*
                Two floats at the center location of the Camera's *poly*.
        """
        bounds = self.poly.bounds
        centerRa = np.mean([bounds[0], bounds[2]]) + raOffset
        centerDec = np.mean([bounds[1], bounds[3]]) + decOffset
        return centerRa, centerDec

    def get_centroid(self, raOffset=0, decOffset=0):
        """
        Returns the geometric centroid of the Camera's *poly*, as
        calculated by the Shapely package. The centroid is returned in
        degrees. User can apply a forced offset to the right ascension or
        declination to the centroid if there is a known asymmetry in the
        Camera's design.

        Parameters:
            raOffset : *float*
                The number of degrees by which to offset the *poly*
                centroid in right ascension.
            decOffset : *float*
                The number of degrees by which to offset the *poly*
                centroid in declination.

        Returns:
            centroidRa, centroidDec : *float*
                Two floats at the centroid location of the Camera's *poly*.
        """
        if self.poly.type == 'Polygon':
            for x, y in self.poly.centroid.coords:
                return (x, y)
        else:
            centroidXList = []
            centroidYList = []
            for poly in self.poly:
                for x, y in self.poly.centroid.coords:
                    centroidXList.append(x)
                    centroidYList.append(y)

        centroidRa = np.mean(centroidXList) + raOffset
        centroidDec = np.mean(centroidYList) + decOffset
        return centroidRa, centroidDec

    def intersect(self, camera):
        """
        Calculates the intersection between this Camera's *poly* and the
        *poly* of the *camera* passed as a parameter. The intersection is
        then returned as a Camera object.

        Parameters:
            camera : *camera.Camera* object
                An object from the camera.Camera class containing a *poly*
                and a *coordsList*.

        Returns:
            camera : *camera.Camera* object
                An object from the camera.Camera class that is the
                intersection between this Camera and the *camera*
                parameter.
        """
        intersectPoly = self.poly.intersection(camera.poly)
        coordsList = self._get_coordsList(intersectPoly)
        return Camera(coordsList)

    def union(self, camera):
        """
        Calculates the union between this Camera's *poly* and the
        *poly* of the *camera* passed as a parameter. The union is
        then returned as a Camera object.

        Parameters:
            camera : *camera.Camera* object
                An object from the camera.Camera class containing a *poly*
                and a *coordsList*.

        Returns:
            camera : *camera.Camera* object
                An object from the camera.Camera class that is the
                union between this Camera and the *camera*
                parameter.
        """
        unionPoly = cascaded_union([self.poly, camera.poly])
        coordsList = self._get_coordsList(unionPoly)
        return Camera(coordsList)

    def difference(self, camera):
        """
        Calculates the difference between this Camera's *poly* and the
        *poly* of the *camera* passed as a parameter. The difference is
        then returned as a Camera object.

        Parameters:
            camera : *camera.Camera* object
                An object from the camera.Camera class containing a *poly*
                and a *coordsList*.

        Returns:
            camera : *camera.Camera* object
                An object from the camera.Camera class that is the
                difference between this Camera and the *camera*
                parameter.
        """
        differencePoly = self.poly.difference(camera.poly)
        coordsList = self._get_coordsList(differencePoly)
        return Camera(coordsList)

    def plot(self, ax,
             color='k',
             alpha=0.5,
             xlim=None,
             ylim=None):
        """
        Plots the Camera's *poly* onto an axis object from Matplotlib.
        The user can specify the color and transparency of *poly*. Unless
        the xlim and ylim of the Matplotlib axis is specified by the user,
        this command will set the limits of the axis to surround just the
        Camera's *poly*.

        Parameters:
            ax : *matplotlib.axes._subplots.AxesSubplot*
                A Matplotlib axes object from the plt.subplots() command.
            color : *str*
                A color string compatible with a Matplotlib axis specifying
                the color of the *poly*.
            alpha : *float*
                A number between 0 and 1 specifying the transparency of
                the *poly*
            xlim : *tuple* of *floats*
                The range of x values with which to plot the *poly*
            ylim : *tuple* of *floats*
                The range of y values with which to plot the *poly*

        Example:
            1) For a single Camera object
                camera = Camera(coordsList)
                fig,ax = plt.subplots()
                camera.plot(ax, color='g', alpha=0.3)

            2) For multiple Camera objects
                camera = Camera(coordsList)
                camera2 = Camera(coordsList)
                camera2.translate(raOffset=1.0)
                fig,ax = plt.subplots()
                camera.plot(ax,
                            color='g',
                            alpha=0.3,
                            xlim=(-2,2),
                            ylim=(-2,2))
                camera2.plot(ax,
                             color='b',
                             alpha=0.3,
                             xlim=(-2,2),
                             ylim=(-2,2))
        """
        ax.add_patch(PolygonPatch(self.poly,
                                  fc=color,
                                  alpha=alpha))

        if xlim is None or ylim is None:
            xlimPoly, ylimPoly = self.get_limits()

        if xlim is None:
            ax.set_xlim(xlimPoly)
        else:
            ax.set_xlim(xlim)

        if ylim is None:
            ax.set_ylim(ylimPoly)
        else:
            ax.set_ylim(ylim)

emptyCamera = Camera([[(0, 0), (0, 0), (0, 0)]])

##############################
#                            #
#  Return Known Cameras      #
#                            #
##############################

def return_machoCamera():
    """
    Returns the CCD coordinates of the MACHO camera as a camera.Camera
    object.
    """
    from skysight import corners
    corners = corners.load_machoCorners()
    machoCamera = Camera([corners], name='macho')
    return machoCamera

def return_hscCamera():
    """
    Returns the CCD coordinates of the Hyper-Supreme Camera as a
    camera.Camera object.
    """
    from skysight import corners
    corners = corners.load_hscCorners()
    hscCamera = Camera(corners, name='hsc')
    return hscCamera

def return_decamCamera():
    """
    Returns the CCD coordinates of the Dark Energy Camera as a
    camera.Camera object.
    """
    from skysight import corners
    corners = corners.load_decamCorners()
    decamCamera = Camera(corners, name='decam')
    return decamCamera


# -*- coding: utf-8 -*-
"""
Colour
======

`Colour <https://github.com/colour-science/colour>`_ is an open-source
`Python <https://www.python.org/>`_ package providing a comprehensive number of
algorithms and datasets for colour science.

It is freely available under the
`New BSD License <https://opensource.org/licenses/BSD-3-Clause>`_ terms.

Sub-packages
------------
-   adaptation: Chromatic adaptation models and transformations.
-   algebra: Algebra utilities.
-   appearance: Colour appearance models.
-   biochemistry: Biochemistry computations.
-   blindness: Colour vision deficiency models.
-   characterisation: Colour fitting and camera characterisation.
-   colorimetry: Core objects for colour computations.
-   constants: *CIE* and *CODATA* constants.
-   continuous: Base objects for continuous data representation.
-   contrast: Objects for contrast sensitivity computation.
-   corresponding: Corresponding colour chromaticities computations.
-   difference: Colour difference computations.
-   examples: Examples for the sub-packages.
-   graph: Graph for automatic colour conversions.
-   io: Input / output objects for reading and writing data.
-   models: Colour models.
-   notation: Colour notation systems.
-   phenomena: Computation of various optical phenomena.
-   plotting: Diagrams, figures, etc...
-   quality: Colour quality computation.
-   recovery: Reflectance recovery.
-   temperature: Colour temperature and correlated colour temperature
    computation.
-   utilities: Various utilities and data structures.
-   volume: Colourspace volumes computation and optimal colour stimuli.
"""

from __future__ import absolute_import

import numpy as np
import sys

from .utilities.deprecation import ModuleAPI, build_API_changes
from .utilities.documentation import is_documentation_building
from .utilities.common import (domain_range_scale, get_domain_range_scale,
                               set_domain_range_scale)

from .adaptation import (CHROMATIC_ADAPTATION_METHODS,
                         CHROMATIC_ADAPTATION_TRANSFORMS,
                         CMCCAT2000_VIEWING_CONDITIONS, chromatic_adaptation)
from .algebra import (CubicSplineInterpolator, Extrapolator,
                      KernelInterpolator, NearestNeighbourInterpolator,
                      LinearInterpolator, NullInterpolator, PchipInterpolator,
                      SpragueInterpolator, TABLE_INTERPOLATION_METHODS,
                      kernel_cardinal_spline, kernel_lanczos, kernel_linear,
                      kernel_nearest_neighbour, kernel_sinc,
                      table_interpolation, lagrange_coefficients)
from .colorimetry import (
    ASTME308_PRACTISE_SHAPE, BANDPASS_CORRECTION_METHODS, CMFS,
    DEFAULT_SPECTRAL_SHAPE, HUNTERLAB_ILLUMINANTS, ILLUMINANTS,
    ILLUMINANTS_SDS, LEFS, LIGHTNESS_METHODS, LIGHT_SOURCES, LIGHT_SOURCES_SDS,
    LMS_CMFS, LUMINANCE_METHODS, MULTI_SD_TO_XYZ_METHODS,
    MultiSpectralDistributions, PHOTOPIC_LEFS, RGB_CMFS, SCOTOPIC_LEFS,
    SD_GAUSSIAN_METHODS, SD_MULTI_LEDS_METHODS, SD_SINGLE_LED_METHODS,
    SD_TO_XYZ_METHODS, STANDARD_OBSERVERS_CMFS, SpectralDistribution,
    SpectralShape, WHITENESS_METHODS, YELLOWNESS_METHODS, bandpass_correction,
    colorimetric_purity, complementary_wavelength, dominant_wavelength,
    excitation_purity, lightness, luminance, luminous_efficacy,
    luminous_efficiency, luminous_flux, multi_sds_to_XYZ,
    sd_CIE_standard_illuminant_A, sd_CIE_illuminant_D_series, sd_blackbody,
    sd_constant, sd_gaussian, sd_mesopic_luminous_efficiency_function,
    sd_multi_leds, sd_ones, sd_single_led, sd_zeros, sd_to_XYZ,
    wavelength_to_XYZ, whiteness, yellowness)
from .blindness import (
    CVD_MATRICES_MACHADO2010, anomalous_trichromacy_cmfs_Machado2009,
    anomalous_trichromacy_matrix_Machado2009, cvd_matrix_Machado2009)
from .appearance import (
    ATD95_Specification, CAM16_Specification, CAM16_VIEWING_CONDITIONS,
    CAM16_to_XYZ, CIECAM02_Specification, CIECAM02_VIEWING_CONDITIONS,
    CIECAM02_to_XYZ, HUNT_VIEWING_CONDITIONS, Hunt_Specification,
    LLAB_Specification, LLAB_VIEWING_CONDITIONS, Nayatani95_Specification,
    RLAB_D_FACTOR, RLAB_Specification, RLAB_VIEWING_CONDITIONS, XYZ_to_ATD95,
    XYZ_to_CAM16, XYZ_to_CIECAM02, XYZ_to_Hunt, XYZ_to_LLAB, XYZ_to_Nayatani95,
    XYZ_to_RLAB)
from .difference import DELTA_E_METHODS, delta_E
from .characterisation import (
    CAMERAS_RGB_SPECTRAL_SENSITIVITIES, COLOURCHECKERS, COLOURCHECKERS_SDS,
    DISPLAYS_RGB_PRIMARIES, POLYNOMIAL_EXPANSION_METHODS, polynomial_expansion,
    COLOUR_CORRECTION_MATRIX_METHODS, colour_correction_matrix,
    COLOUR_CORRECTION_METHODS, colour_correction)
from .io import (LUT1D, LUT3x1D, LUT3D, LUTSequence, READ_IMAGE_METHODS,
                 SpectralDistribution_IESTM2714, WRITE_IMAGE_METHODS,
                 read_image, read_LUT, read_sds_from_csv_file,
                 read_sds_from_xrite_file, read_spectral_data_from_csv_file,
                 write_image, write_LUT, write_sds_to_csv_file)
from .models import (
    CAM02LCD_to_JMh_CIECAM02, CAM02SCD_to_JMh_CIECAM02,
    CAM02UCS_to_JMh_CIECAM02, CAM16LCD_to_JMh_CAM16, CAM16SCD_to_JMh_CAM16,
    CAM16UCS_to_JMh_CAM16, CCTF_DECODINGS, CCTF_ENCODINGS, CMYK_to_CMY,
    CMY_to_CMYK, CMY_to_RGB, CV_range, DIN99_to_Lab, EOTFS, EOTF_INVERSES,
    HDR_CIELAB_METHODS, HDR_IPT_METHODS, HSL_to_RGB, HSV_to_RGB,
    Hunter_Lab_to_XYZ, Hunter_Rdab_to_XYZ, ICTCP_to_RGB, IPT_hue_angle,
    IPT_to_XYZ, JMh_CAM16_to_CAM16LCD, JMh_CAM16_to_CAM16SCD,
    JMh_CAM16_to_CAM16UCS, JMh_CIECAM02_to_CAM02LCD, JMh_CIECAM02_to_CAM02SCD,
    JMh_CIECAM02_to_CAM02UCS, JzAzBz_to_XYZ, LCHab_to_Lab, LCHuv_to_Luv,
    LOG_DECODINGS, LOG_ENCODINGS, Lab_to_DIN99, Lab_to_LCHab, Lab_to_XYZ,
    Luv_to_LCHuv, Luv_to_XYZ, Luv_to_uv, Luv_uv_to_xy,
    MACADAM_1942_ELLIPSES_DATA, OETFS, OETF_INVERSES, OOTFS, OOTF_INVERSES,
    OSA_UCS_to_XYZ, POINTER_GAMUT_BOUNDARIES, POINTER_GAMUT_DATA,
    POINTER_GAMUT_ILLUMINANT, Prismatic_to_RGB, RGB_COLOURSPACES,
    RGB_Colourspace, RGB_luminance, RGB_luminance_equation, RGB_to_CMY,
    RGB_to_HSL, RGB_to_HSV, RGB_to_ICTCP, RGB_to_Prismatic, RGB_to_RGB,
    RGB_to_RGB_matrix, RGB_to_XYZ, RGB_to_YCbCr, RGB_to_YcCbcCrc, RGB_to_YCoCg,
    UCS_to_XYZ, UCS_to_uv, UCS_uv_to_xy, UVW_to_XYZ, XYZ_to_Hunter_Lab,
    XYZ_to_Hunter_Rdab, XYZ_to_IPT, XYZ_to_JzAzBz, XYZ_to_K_ab_HunterLab1966,
    XYZ_to_Lab, XYZ_to_Luv, XYZ_to_OSA_UCS, XYZ_to_RGB, XYZ_to_UCS, XYZ_to_UVW,
    XYZ_to_hdr_CIELab, XYZ_to_hdr_IPT, XYZ_to_sRGB, XYZ_to_xy, XYZ_to_xyY,
    YCBCR_WEIGHTS, YCbCr_to_RGB, YcCbcCrc_to_RGB, YCoCg_to_RGB, cctf_decoding,
    cctf_encoding, chromatically_adapted_primaries, eotf, eotf_inverse,
    full_to_legal, gamma_function, hdr_CIELab_to_XYZ, hdr_IPT_to_XYZ,
    legal_to_full, linear_function, log_decoding, log_encoding,
    normalised_primary_matrix, oetf, oetf_inverse, ootf, ootf_inverse,
    primaries_whitepoint, sd_to_aces_relative_exposure_values, sRGB_to_XYZ,
    uv_to_Luv, uv_to_UCS, xyY_to_XYZ, xyY_to_xy, xy_to_Luv_uv, xy_to_UCS_uv,
    xy_to_XYZ, xy_to_xyY)
from .corresponding import (
    BRENEMAN_EXPERIMENTS, BRENEMAN_EXPERIMENTS_PRIMARIES_CHROMATICITIES,
    CORRESPONDING_CHROMATICITIES_PREDICTION_MODELS, CorrespondingColourDataset,
    CorrespondingChromaticitiesPrediction,
    corresponding_chromaticities_prediction)
from .contrast import (CONTRAST_SENSITIVITY_METHODS,
                       contrast_sensitivity_function)
from .phenomena import (rayleigh_scattering, scattering_cross_section,
                        sd_rayleigh_scattering)
from .notation import (MUNSELL_COLOURS, MUNSELL_VALUE_METHODS,
                       munsell_colour_to_xyY, munsell_value,
                       xyY_to_munsell_colour)
from .quality import (COLOUR_QUALITY_SCALE_METHODS, colour_quality_scale,
                      colour_rendering_index)
from .recovery import XYZ_TO_SD_METHODS, XYZ_to_sd
from .temperature import (CCT_TO_UV_METHODS, CCT_TO_XY_METHODS, CCT_to_uv,
                          CCT_to_xy, UV_TO_CCT_METHODS, XY_TO_CCT_METHODS,
                          uv_to_CCT, xy_to_CCT)
from .volume import (
    ILLUMINANTS_OPTIMAL_COLOUR_STIMULI, RGB_colourspace_limits,
    RGB_colourspace_pointer_gamut_coverage_MonteCarlo,
    RGB_colourspace_visible_spectrum_coverage_MonteCarlo,
    RGB_colourspace_volume_MonteCarlo,
    RGB_colourspace_volume_coverage_MonteCarlo, is_within_macadam_limits,
    is_within_mesh_volume, is_within_pointer_gamut, is_within_visible_spectrum)
from .graph import describe_conversion_path, convert

__author__ = 'Colour Developers'
__copyright__ = 'Copyright (C) 2013-2019 - 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__ = [
    'domain_range_scale', 'get_domain_range_scale', 'set_domain_range_scale'
]
__all__ += [
    'CHROMATIC_ADAPTATION_METHODS', 'CHROMATIC_ADAPTATION_TRANSFORMS',
    'CMCCAT2000_VIEWING_CONDITIONS', 'chromatic_adaptation'
]
__all__ += [
    'CubicSplineInterpolator', 'Extrapolator', 'KernelInterpolator',
    'NearestNeighbourInterpolator', 'LinearInterpolator', 'NullInterpolator',
    'PchipInterpolator', 'SpragueInterpolator', 'TABLE_INTERPOLATION_METHODS',
    'kernel_cardinal_spline', 'kernel_lanczos', 'kernel_linear',
    'kernel_nearest_neighbour', 'kernel_sinc', 'table_interpolation',
    'lagrange_coefficients'
]
__all__ += [
    'ASTME308_PRACTISE_SHAPE', 'BANDPASS_CORRECTION_METHODS', 'CMFS',
    'DEFAULT_SPECTRAL_SHAPE', 'HUNTERLAB_ILLUMINANTS', 'ILLUMINANTS',
    'ILLUMINANTS_SDS', 'LEFS', 'LIGHTNESS_METHODS', 'LIGHT_SOURCES',
    'LIGHT_SOURCES_SDS', 'LMS_CMFS', 'LUMINANCE_METHODS',
    'MULTI_SD_TO_XYZ_METHODS', 'MultiSpectralDistributions', 'PHOTOPIC_LEFS',
    'RGB_CMFS', 'SCOTOPIC_LEFS', 'SD_GAUSSIAN_METHODS',
    'SD_MULTI_LEDS_METHODS', 'SD_SINGLE_LED_METHODS', 'SD_TO_XYZ_METHODS',
    'STANDARD_OBSERVERS_CMFS', 'SpectralDistribution', 'SpectralShape',
    'WHITENESS_METHODS', 'YELLOWNESS_METHODS', 'bandpass_correction',
    'colorimetric_purity', 'complementary_wavelength', 'dominant_wavelength',
    'excitation_purity', 'lightness', 'luminance', 'luminous_efficacy',
    'luminous_efficiency', 'luminous_flux', 'multi_sds_to_XYZ',
    'sd_CIE_standard_illuminant_A', 'sd_CIE_illuminant_D_series',
    'sd_blackbody', 'sd_constant', 'sd_gaussian',
    'sd_mesopic_luminous_efficiency_function', 'sd_multi_leds', 'sd_ones',
    'sd_zeros', 'sd_single_led', 'sd_to_XYZ', 'wavelength_to_XYZ', 'whiteness',
    'yellowness'
]
__all__ += [
    'CVD_MATRICES_MACHADO2010', 'anomalous_trichromacy_cmfs_Machado2009',
    'anomalous_trichromacy_matrix_Machado2009', 'cvd_matrix_Machado2009'
]
__all__ += [
    'ATD95_Specification', 'CAM16_Specification', 'CAM16_VIEWING_CONDITIONS',
    'CAM16_to_XYZ', 'CIECAM02_Specification', 'CIECAM02_VIEWING_CONDITIONS',
    'CIECAM02_to_XYZ', 'HUNT_VIEWING_CONDITIONS', 'Hunt_Specification',
    'LLAB_Specification', 'LLAB_VIEWING_CONDITIONS',
    'Nayatani95_Specification', 'RLAB_D_FACTOR', 'RLAB_Specification',
    'RLAB_VIEWING_CONDITIONS', 'XYZ_to_ATD95', 'XYZ_to_CAM16',
    'XYZ_to_CIECAM02', 'XYZ_to_Hunt', 'XYZ_to_LLAB', 'XYZ_to_Nayatani95',
    'XYZ_to_RLAB'
]
__all__ += ['DELTA_E_METHODS', 'delta_E']
__all__ += [
    'CAMERAS_RGB_SPECTRAL_SENSITIVITIES', 'COLOURCHECKERS',
    'COLOURCHECKERS_SDS', 'DISPLAYS_RGB_PRIMARIES',
    'POLYNOMIAL_EXPANSION_METHODS', 'polynomial_expansion',
    'COLOUR_CORRECTION_MATRIX_METHODS', 'colour_correction_matrix',
    'COLOUR_CORRECTION_METHODS', 'colour_correction'
]
__all__ += [
    'LUT1D', 'LUT3x1D', 'LUT3D', 'LUTSequence', 'READ_IMAGE_METHODS',
    'SpectralDistribution_IESTM2714', 'WRITE_IMAGE_METHODS', 'read_image',
    'read_LUT', 'read_sds_from_csv_file', 'read_sds_from_xrite_file',
    'read_spectral_data_from_csv_file', 'write_image', 'write_LUT',
    'write_sds_to_csv_file'
]
__all__ += [
    'CAM02LCD_to_JMh_CIECAM02', 'CAM02SCD_to_JMh_CIECAM02',
    'CAM02UCS_to_JMh_CIECAM02', 'CAM16LCD_to_JMh_CAM16',
    'CAM16SCD_to_JMh_CAM16', 'CAM16UCS_to_JMh_CAM16', 'CCTF_DECODINGS',
    'CCTF_ENCODINGS', 'CMYK_to_CMY', 'CMY_to_CMYK', 'CMY_to_RGB', 'CV_range',
    'DIN99_to_Lab', 'EOTFS', 'EOTF_INVERSES', 'HDR_CIELAB_METHODS',
    'HDR_IPT_METHODS', 'HSL_to_RGB', 'HSV_to_RGB', 'Hunter_Lab_to_XYZ',
    'Hunter_Rdab_to_XYZ', 'ICTCP_to_RGB', 'IPT_hue_angle', 'IPT_to_XYZ',
    'JMh_CAM16_to_CAM16LCD', 'JMh_CAM16_to_CAM16SCD', 'JMh_CAM16_to_CAM16UCS',
    'JMh_CIECAM02_to_CAM02LCD', 'JMh_CIECAM02_to_CAM02SCD',
    'JMh_CIECAM02_to_CAM02UCS', 'JzAzBz_to_XYZ', 'LCHab_to_Lab',
    'LCHuv_to_Luv', 'LOG_DECODINGS', 'LOG_ENCODINGS', 'Lab_to_DIN99',
    'Lab_to_LCHab', 'Lab_to_XYZ', 'Luv_to_LCHuv', 'Luv_to_XYZ', 'Luv_to_uv',
    'Luv_uv_to_xy', 'OETFS', 'OETF_INVERSES', 'OOTFS',
    'MACADAM_1942_ELLIPSES_DATA', 'OOTF_INVERSES', 'OSA_UCS_to_XYZ',
    'POINTER_GAMUT_BOUNDARIES', 'POINTER_GAMUT_DATA',
    'POINTER_GAMUT_ILLUMINANT', 'Prismatic_to_RGB', 'RGB_COLOURSPACES',
    'RGB_Colourspace', 'RGB_luminance', 'RGB_luminance_equation', 'RGB_to_CMY',
    'RGB_to_HSL', 'RGB_to_HSV', 'RGB_to_ICTCP', 'RGB_to_Prismatic',
    'RGB_to_RGB', 'RGB_to_RGB_matrix', 'RGB_to_XYZ', 'RGB_to_YCbCr',
    'RGB_to_YcCbcCrc', 'RGB_to_YCoCg', 'UCS_to_XYZ', 'UCS_to_uv',
    'UCS_uv_to_xy', 'UVW_to_XYZ', 'XYZ_to_Hunter_Lab', 'XYZ_to_Hunter_Rdab',
    'XYZ_to_IPT', 'XYZ_to_JzAzBz', 'XYZ_to_K_ab_HunterLab1966', 'XYZ_to_Lab',
    'XYZ_to_Luv', 'XYZ_to_OSA_UCS', 'XYZ_to_RGB', 'XYZ_to_UCS', 'XYZ_to_UVW',
    'XYZ_to_hdr_CIELab', 'XYZ_to_hdr_IPT', 'XYZ_to_sRGB', 'XYZ_to_xy',
    'XYZ_to_xyY', 'YCBCR_WEIGHTS', 'YCbCr_to_RGB', 'YcCbcCrc_to_RGB',
    'YCoCg_to_RGB', 'cctf_decoding', 'cctf_encoding',
    'chromatically_adapted_primaries', 'eotf', 'eotf_inverse', 'full_to_legal',
    'gamma_function', 'hdr_CIELab_to_XYZ', 'hdr_IPT_to_XYZ', 'legal_to_full',
    'linear_function', 'log_decoding', 'log_encoding',
    'normalised_primary_matrix', 'oetf', 'oetf_inverse', 'ootf',
    'ootf_inverse', 'primaries_whitepoint',
    'sd_to_aces_relative_exposure_values', 'sRGB_to_XYZ', 'uv_to_Luv',
    'uv_to_UCS', 'xyY_to_XYZ', 'xyY_to_xy', 'xy_to_Luv_uv', 'xy_to_UCS_uv',
    'xy_to_XYZ', 'xy_to_xyY'
]
__all__ += [
    'BRENEMAN_EXPERIMENTS', 'BRENEMAN_EXPERIMENTS_PRIMARIES_CHROMATICITIES',
    'CORRESPONDING_CHROMATICITIES_PREDICTION_MODELS',
    'CorrespondingColourDataset', 'CorrespondingChromaticitiesPrediction',
    'corresponding_chromaticities_prediction'
]
__all__ += ['CONTRAST_SENSITIVITY_METHODS', 'contrast_sensitivity_function']
__all__ += [
    'rayleigh_scattering', 'scattering_cross_section', 'sd_rayleigh_scattering'
]
__all__ += [
    'MUNSELL_COLOURS', 'MUNSELL_VALUE_METHODS', 'munsell_colour_to_xyY',
    'munsell_value', 'xyY_to_munsell_colour'
]
__all__ += [
    'COLOUR_QUALITY_SCALE_METHODS', 'colour_quality_scale',
    'colour_rendering_index'
]
__all__ += ['XYZ_TO_SD_METHODS', 'XYZ_to_sd']
__all__ += [
    'CCT_TO_UV_METHODS', 'CCT_TO_XY_METHODS', 'CCT_to_uv', 'CCT_to_xy',
    'UV_TO_CCT_METHODS', 'XY_TO_CCT_METHODS', 'uv_to_CCT', 'xy_to_CCT'
]
__all__ += [
    'ILLUMINANTS_OPTIMAL_COLOUR_STIMULI', 'RGB_colourspace_limits',
    'RGB_colourspace_pointer_gamut_coverage_MonteCarlo',
    'RGB_colourspace_visible_spectrum_coverage_MonteCarlo',
    'RGB_colourspace_volume_MonteCarlo',
    'RGB_colourspace_volume_coverage_MonteCarlo', 'is_within_macadam_limits',
    'is_within_mesh_volume', 'is_within_pointer_gamut',
    'is_within_visible_spectrum'
]
__all__ += ['describe_conversion_path', 'convert']

__application_name__ = 'Colour'

__major_version__ = '0'
__minor_version__ = '3'
__change_version__ = '14'
__version__ = '.'.join(
    (__major_version__,
     __minor_version__,
     __change_version__))  # yapf: disable

# TODO: Remove legacy printing support when deemed appropriate.
try:
    np.set_printoptions(legacy='1.13')
except TypeError:  # pragma: no cover
    pass

# ----------------------------------------------------------------------------#
# ---                API Changes and Deprecation Management                ---#
# ----------------------------------------------------------------------------#
class colour(ModuleAPI):
    def __getattr__(self, attribute):
        return super(colour, self).__getattr__(attribute)

colour.__application_name__ = __application_name__

colour.__major_version__ = __major_version__
colour.__minor_version__ = __minor_version__
colour.__change_version__ = __change_version__
colour.__version__ = __version__

# v0.3.11
API_CHANGES = {
    'ObjectFutureAccessChange': [
        [
            'colour.ACES_2065_1_COLOURSPACE',
            'colour.models.ACES_2065_1_COLOURSPACE',
        ],
        [
            'colour.ACES_CCT_COLOURSPACE',
            'colour.models.ACES_CCT_COLOURSPACE',
        ],
        [
            'colour.ACES_CC_COLOURSPACE',
            'colour.models.ACES_CC_COLOURSPACE',
        ],
        [
            'colour.ACES_CG_COLOURSPACE',
            'colour.models.ACES_CG_COLOURSPACE',
        ],
        [
            'colour.ACES_PROXY_COLOURSPACE',
            'colour.models.ACES_PROXY_COLOURSPACE',
        ],
        [
            'colour.ACES_RICD',
            'colour.models.ACES_RICD',
        ],
        [
            'colour.ADOBE_RGB_1998_COLOURSPACE',
            'colour.models.ADOBE_RGB_1998_COLOURSPACE',
        ],
        [
            'colour.ADOBE_WIDE_GAMUT_RGB_COLOURSPACE',
            'colour.models.ADOBE_WIDE_GAMUT_RGB_COLOURSPACE',
        ],
        [
            'colour.ALEXA_WIDE_GAMUT_COLOURSPACE',
            'colour.models.ALEXA_WIDE_GAMUT_COLOURSPACE',
        ],
        [
            'colour.APPLE_RGB_COLOURSPACE',
            'colour.models.APPLE_RGB_COLOURSPACE',
        ],
        [
            'colour.AVOGADRO_CONSTANT',
            'colour.constants.AVOGADRO_CONSTANT',
        ],
        [
            'colour.AbstractContinuousFunction',
            'colour.continuous.AbstractContinuousFunction',
        ],
        [
            'colour.BEST_RGB_COLOURSPACE',
            'colour.models.BEST_RGB_COLOURSPACE',
        ],
        [
            'colour.BETA_RGB_COLOURSPACE',
            'colour.models.BETA_RGB_COLOURSPACE',
        ],
        [
            'colour.BOLTZMANN_CONSTANT',
            'colour.constants.BOLTZMANN_CONSTANT',
        ],
        [
            'colour.BRADFORD_CAT',
            'colour.adaptation.BRADFORD_CAT',
        ],
        [
            'colour.BS_CAT',
            'colour.adaptation.BS_CAT',
        ],
        [
            'colour.BS_PC_CAT',
            'colour.adaptation.BS_PC_CAT',
        ],
        [
            'colour.BT2020_COLOURSPACE',
            'colour.models.BT2020_COLOURSPACE',
        ],
        [
            'colour.BT470_525_COLOURSPACE',
            'colour.models.BT470_525_COLOURSPACE',
        ],
        [
            'colour.BT470_625_COLOURSPACE',
            'colour.models.BT470_625_COLOURSPACE',
        ],
        [
            'colour.BT709_COLOURSPACE',
            'colour.models.BT709_COLOURSPACE',
        ],
        [
            'colour.CAM16_InductionFactors',
            'colour.appearance.CAM16_InductionFactors',
        ],
        [
            'colour.CAT02_BRILL_CAT',
            'colour.adaptation.CAT02_BRILL_CAT',
        ],
        [
            'colour.CAT02_CAT',
            'colour.adaptation.CAT02_CAT',
        ],
        [
            'colour.CCT_to_uv_Krystek1985',
            'colour.temperature.CCT_to_uv_Krystek1985',
        ],
        [
            'colour.CCT_to_uv_Ohno2013',
            'colour.temperature.CCT_to_uv_Ohno2013',
        ],
        [
            'colour.CCT_to_uv_Robertson1968',
            'colour.temperature.CCT_to_uv_Robertson1968',
        ],
        [
            'colour.CCT_to_xy_CIE_D',
            'colour.temperature.CCT_to_xy_CIE_D',
        ],
        [
            'colour.CCT_to_xy_Kang2002',
            'colour.temperature.CCT_to_xy_Kang2002',
        ],
        [
            'colour.CIECAM02_InductionFactors',
            'colour.appearance.CIECAM02_InductionFactors',
        ],
        [
            'colour.CIE_RGB_COLOURSPACE',
            'colour.models.CIE_RGB_COLOURSPACE',
        ],
        [
            'colour.CINEMA_GAMUT_COLOURSPACE',
            'colour.models.CINEMA_GAMUT_COLOURSPACE',
        ],
        [
            'colour.CMCCAT2000_CAT',
            'colour.adaptation.CMCCAT2000_CAT',
        ],
        [
            'colour.CMCCAT2000_InductionFactors',
            'colour.adaptation.CMCCAT2000_InductionFactors',
        ],
        [
            'colour.CMCCAT97_CAT',
            'colour.adaptation.CMCCAT97_CAT',
        ],
        [
            'colour.COLOR_MATCH_RGB_COLOURSPACE',
            'colour.models.COLOR_MATCH_RGB_COLOURSPACE',
        ],
        [
            'colour.COLOURCHECKER_INDEXES_TO_NAMES_MAPPING',
            'colour.characterisation.COLOURCHECKER_INDEXES_TO_NAMES_MAPPING',
        ],
        [
            'colour.COLOURSPACE_MODELS',
            'colour.models.COLOURSPACE_MODELS',
        ],
        [
            'colour.COLOURSPACE_MODELS_LABELS',
            'colour.models.COLOURSPACE_MODELS_AXIS_LABELS',
        ],
        [
            'colour.CQS_Specification',
            'colour.quality.CQS_Specification',
        ],
        [
            'colour.CRI_Specification',
            'colour.quality.CRI_Specification',
        ],
        [
            'colour.CaseInsensitiveMapping',
            'colour.utilities.CaseInsensitiveMapping',
        ],
        [
            'colour.ColourWarning',
            'colour.utilities.ColourWarning',
        ],
        [
            'colour.DCI_P3_COLOURSPACE',
            'colour.models.DCI_P3_COLOURSPACE',
        ],
        [
            'colour.DCI_P3_P_COLOURSPACE',
            'colour.models.DCI_P3_P_COLOURSPACE',
        ],
        [
            'colour.DEFAULT_FLOAT_DTYPE',
            'colour.constants.DEFAULT_FLOAT_DTYPE',
        ],
        [
            'colour.DON_RGB_4_COLOURSPACE',
            'colour.models.DON_RGB_4_COLOURSPACE',
        ],
        [
            'colour.DRAGON_COLOR_2_COLOURSPACE',
            'colour.models.DRAGON_COLOR_2_COLOURSPACE',
        ],
        [
            'colour.DRAGON_COLOR_COLOURSPACE',
            'colour.models.DRAGON_COLOR_COLOURSPACE',
        ],
        [
            'colour.D_ILLUMINANTS_S_SPDS',
            'colour.colorimetry.D_ILLUMINANTS_S_SDS',
        ],
        [
            'colour.ECI_RGB_V2_COLOURSPACE',
            'colour.models.ECI_RGB_V2_COLOURSPACE',
        ],
        [
            'colour.EKTA_SPACE_PS_5_COLOURSPACE',
            'colour.models.EKTA_SPACE_PS_5_COLOURSPACE',
        ],
        [
            'colour.EPSILON',
            'colour.constants.EPSILON',
        ],
        [
            'colour.ERIMM_RGB_COLOURSPACE',
            'colour.models.ERIMM_RGB_COLOURSPACE',
        ],
        [
            'colour.FAIRCHILD_CAT',
            'colour.adaptation.FAIRCHILD_CAT',
        ],
        [
            'colour.FLOATING_POINT_NUMBER_PATTERN',
            'colour.constants.FLOATING_POINT_NUMBER_PATTERN',
        ],
        [
            'colour.Hunt_InductionFactors',
            'colour.appearance.Hunt_InductionFactors',
        ],
        [
            'colour.INTEGER_THRESHOLD',
            'colour.constants.INTEGER_THRESHOLD',
        ],
        [
            'colour.KP_M',
            'colour.constants.KP_M',
        ],
        [
            'colour.K_M',
            'colour.constants.K_M',
        ],
        [
            'colour.LIGHT_SPEED',
            'colour.constants.LIGHT_SPEED',
        ],
        [
            'colour.LLAB_InductionFactors',
            'colour.appearance.LLAB_InductionFactors',
        ],
        [
            'colour.LMS_10_degree_cmfs_to_XYZ_10_degree_cmfs',
            'colour.colorimetry.LMS_10_degree_cmfs_to_XYZ_10_degree_cmfs',
        ],
        [
            'colour.LMS_2_degree_cmfs_to_XYZ_2_degree_cmfs',
            'colour.colorimetry.LMS_2_degree_cmfs_to_XYZ_2_degree_cmfs',
        ],
        [
            'colour.LMS_ConeFundamentals',
            'colour.colorimetry.LMS_ConeFundamentals',
        ],
        [
            'colour.LineSegmentsIntersections_Specification',
            'colour.algebra.LineSegmentsIntersections_Specification',
        ],
        [
            'colour.Lookup',
            'colour.utilities.Lookup',
        ],
        [
            'colour.MAX_RGB_COLOURSPACE',
            'colour.models.MAX_RGB_COLOURSPACE',
        ],
        [
            'colour.MUNSELL_COLOURS_1929',
            'colour.notation.MUNSELL_COLOURS_1929',
        ],
        [
            'colour.MUNSELL_COLOURS_ALL',
            'colour.notation.MUNSELL_COLOURS_ALL',
        ],
        [
            'colour.MUNSELL_COLOURS_REAL',
            'colour.notation.MUNSELL_COLOURS_REAL',
        ],
        [
            'colour.MultiSignal',
            'colour.continuous.MultiSignals',
        ],
        [
            'colour.NTSC_1953_COLOURSPACE',
            'colour.models.NTSC_1953_COLOURSPACE',
        ],
        [
            'colour.PAL_SECAM_COLOURSPACE',
            'colour.models.PAL_SECAM_COLOURSPACE',
        ],
        [
            'colour.PLANCK_CONSTANT',
            'colour.constants.PLANCK_CONSTANT',
        ],
        [
            'colour.PROPHOTO_RGB_COLOURSPACE',
            'colour.models.PROPHOTO_RGB_COLOURSPACE',
        ],
        [
            'colour.PROTUNE_NATIVE_COLOURSPACE',
            'colour.models.PROTUNE_NATIVE_COLOURSPACE',
        ],
        [
            'colour.RED_COLOR_2_COLOURSPACE',
            'colour.models.RED_COLOR_2_COLOURSPACE',
        ],
        [
            'colour.RED_COLOR_3_COLOURSPACE',
            'colour.models.RED_COLOR_3_COLOURSPACE',
        ],
        [
            'colour.RED_COLOR_4_COLOURSPACE',
            'colour.models.RED_COLOR_4_COLOURSPACE',
        ],
        [
            'colour.RED_COLOR_COLOURSPACE',
            'colour.models.RED_COLOR_COLOURSPACE',
        ],
        [
            'colour.RED_WIDE_GAMUT_RGB_COLOURSPACE',
            'colour.models.RED_WIDE_GAMUT_RGB_COLOURSPACE',
        ],
        [
            'colour.RGB_10_degree_cmfs_to_LMS_10_degree_cmfs',
            'colour.colorimetry.RGB_10_degree_cmfs_to_LMS_10_degree_cmfs',
        ],
        [
            'colour.RGB_10_degree_cmfs_to_XYZ_10_degree_cmfs',
            'colour.colorimetry.RGB_10_degree_cmfs_to_XYZ_10_degree_cmfs',
        ],
        [
            'colour.RGB_2_degree_cmfs_to_XYZ_2_degree_cmfs',
            'colour.colorimetry.RGB_2_degree_cmfs_to_XYZ_2_degree_cmfs',
        ],
        [
            'colour.RGB_ColourMatchingFunctions',
            'colour.colorimetry.RGB_ColourMatchingFunctions',
        ],
        [
            'colour.RGB_DisplayPrimaries',
            'colour.characterisation.RGB_DisplayPrimaries',
        ],
        [
            'colour.RGB_SpectralSensitivities',
            'colour.characterisation.RGB_SpectralSensitivities',
        ],
        [
            'colour.RGB_to_sd_Smits1999',
            'colour.recovery.RGB_to_sd_Smits1999',
        ],
        [
            'colour.RIMM_RGB_COLOURSPACE',
            'colour.models.RIMM_RGB_COLOURSPACE',
        ],
        [
            'colour.ROMM_RGB_COLOURSPACE',
            'colour.models.ROMM_RGB_COLOURSPACE',
        ],
        [
            'colour.RUSSELL_RGB_COLOURSPACE',
            'colour.models.RUSSELL_RGB_COLOURSPACE',
        ],
        [
            'colour.SHARP_CAT',
            'colour.adaptation.SHARP_CAT',
        ],
        [
            'colour.SMITS_1999_SPDS',
            'colour.recovery.SMITS_1999_SDS',
        ],
        [
            'colour.SMPTE_240M_COLOURSPACE',
            'colour.models.SMPTE_240M_COLOURSPACE',
        ],
        [
            'colour.S_GAMUT3_CINE_COLOURSPACE',
            'colour.models.S_GAMUT3_CINE_COLOURSPACE',
        ],
        [
            'colour.S_GAMUT3_COLOURSPACE',
            'colour.models.S_GAMUT3_COLOURSPACE',
        ],
        [
            'colour.S_GAMUT_COLOURSPACE',
            'colour.models.S_GAMUT_COLOURSPACE',
        ],
        [
            'colour.Signal',
            'colour.continuous.Signal',
        ],
        [
            'colour.Structure',
            'colour.utilities.Structure',
        ],
        [
            'colour.TCS_SPDS',
            'colour.quality.TCS_SDS',
        ],
        [
            'colour.VON_KRIES_CAT',
            'colour.adaptation.VON_KRIES_CAT',
        ],
        [
            'colour.VS_SPDS',
            'colour.quality.VS_SDS',
        ],
        [
            'colour.V_GAMUT_COLOURSPACE',
            'colour.models.V_GAMUT_COLOURSPACE',
        ],
        [
            'colour.XTREME_RGB_COLOURSPACE',
            'colour.models.XTREME_RGB_COLOURSPACE',
        ],
        [
            'colour.XYZ_ColourMatchingFunctions',
            'colour.colorimetry.XYZ_ColourMatchingFunctions',
        ],
        [
            'colour.XYZ_SCALING_CAT',
            'colour.adaptation.XYZ_SCALING_CAT',
        ],
        [
            'colour.XYZ_to_colourspace_model',
            'colour.models.XYZ_to_colourspace_model',
        ],
        [
            'colour.XYZ_to_sd_Meng2015',
            'colour.recovery.XYZ_to_sd_Meng2015',
        ],
        [
            'colour.adjust_tristimulus_weighting_factors_ASTME30815',
            'colour.colorimetry.adjust_tristimulus_weighting_factors_ASTME308',
        ],
        [
            'colour.as_namedtuple',
            'colour.utilities.as_namedtuple',
        ],
        [
            'colour.as_numeric',
            'colour.utilities.as_numeric',
        ],
        [
            'colour.bandpass_correction_Stearns1988',
            'colour.colorimetry.bandpass_correction_Stearns1988',
        ],
        [
            'colour.batch',
            'colour.utilities.batch',
        ],
        [
            'colour.blackbody_spectral_radiance',
            'colour.colorimetry.blackbody_spectral_radiance',
        ],
        [
            'colour.cartesian_to_cylindrical',
            'colour.algebra.cartesian_to_cylindrical',
        ],
        [
            'colour.cartesian_to_polar',
            'colour.algebra.cartesian_to_polar',
        ],
        [
            'colour.cartesian_to_spherical',
            'colour.algebra.cartesian_to_spherical',
        ],
        [
            'colour.centroid',
            'colour.utilities.centroid',
        ],
        [
            'colour.chromatic_adaptation_CIE1994',
            'colour.adaptation.chromatic_adaptation_CIE1994',
        ],
        [
            'colour.chromatic_adaptation_CMCCAT2000',
            'colour.adaptation.chromatic_adaptation_CMCCAT2000',
        ],
        [
            'colour.chromatic_adaptation_Fairchild1990',
            'colour.adaptation.chromatic_adaptation_Fairchild1990',
        ],
        [
            'colour.chromatic_adaptation_VonKries',
            'colour.adaptation.chromatic_adaptation_VonKries',
        ],
        [
            'colour.chromatic_adaptation_forward_CMCCAT2000',
            'colour.adaptation.chromatic_adaptation_forward_CMCCAT2000',
        ],
        [
            'colour.chromatic_adaptation_matrix_VonKries',
            'colour.adaptation.chromatic_adaptation_matrix_VonKries',
        ],
        [
            'colour.chromatic_adaptation_reverse_CMCCAT2000',
            'colour.adaptation.chromatic_adaptation_inverse_CMCCAT2000',
        ],
        [
            'colour.closest',
            'colour.utilities.closest',
        ],
        [
            'colour.closest_indexes',
            'colour.utilities.closest_indexes',
        ],
        [
            'colour.corresponding_chromaticities_prediction_CIE1994',
            'colour.corresponding.corresponding_chromaticities_prediction_CIE1994',  # noqa
        ],
        [
            'colour.corresponding_chromaticities_prediction_CMCCAT2000',
            'colour.corresponding.corresponding_chromaticities_prediction_CMCCAT2000',  # noqa
        ],
        [
            'colour.corresponding_chromaticities_prediction_Fairchild1990',
            'colour.corresponding.corresponding_chromaticities_prediction_Fairchild1990',  # noqa
        ],
        [
            'colour.corresponding_chromaticities_prediction_VonKries',
            'colour.corresponding.corresponding_chromaticities_prediction_VonKries',  # noqa
        ],
        [
            'colour.cylindrical_to_cartesian',
            'colour.algebra.cylindrical_to_cartesian',
        ],
        [
            'colour.delta_E_CAM02LCD',
            'colour.difference.delta_E_CAM02LCD',
        ],
        [
            'colour.delta_E_CAM02SCD',
            'colour.difference.delta_E_CAM02SCD',
        ],
        [
            'colour.delta_E_CAM02UCS',
            'colour.difference.delta_E_CAM02UCS',
        ],
        [
            'colour.delta_E_CAM16LCD',
            'colour.difference.delta_E_CAM16LCD',
        ],
        [
            'colour.delta_E_CAM16SCD',
            'colour.difference.delta_E_CAM16SCD',
        ],
        [
            'colour.delta_E_CAM16UCS',
            'colour.difference.delta_E_CAM16UCS',
        ],
        [
            'colour.delta_E_CIE1976',
            'colour.difference.delta_E_CIE1976',
        ],
        [
            'colour.delta_E_CIE1994',
            'colour.difference.delta_E_CIE1994',
        ],
        [
            'colour.delta_E_CIE2000',
            'colour.difference.delta_E_CIE2000',
        ],
        [
            'colour.delta_E_CMC',
            'colour.difference.delta_E_CMC',
        ],
        [
            'colour.dot_matrix',
            'colour.utilities.dot_matrix',
        ],
        [
            'colour.dot_vector',
            'colour.utilities.dot_vector',
        ],
        [
            'colour.eotf_BT1886',
            'colour.models.eotf_BT1886',
        ],
        [
            'colour.eotf_BT2020',
            'colour.models.eotf_BT2020',
        ],
        [
            'colour.eotf_BT2100_HLG',
            'colour.models.eotf_HLG_BT2100',
        ],
        [
            'colour.eotf_BT2100_PQ',
            'colour.models.eotf_PQ_BT2100',
        ],
        [
            'colour.eotf_DCIP3',
            'colour.models.eotf_DCDM',
        ],
        [
            'colour.eotf_DICOMGSDF',
            'colour.models.eotf_DICOMGSDF',
        ],
        [
            'colour.cctf_decoding_ProPhotoRGB',
            'colour.models.cctf_decoding_ProPhotoRGB',
        ],
        [
            'colour.cctf_decoding_RIMMRGB',
            'colour.models.cctf_decoding_RIMMRGB',
        ],
        [
            'colour.cctf_decoding_ROMMRGB',
            'colour.models.cctf_decoding_ROMMRGB',
        ],
        [
            'colour.eotf_SMPTE240M',
            'colour.models.eotf_SMPTE240M',
        ],
        [
            'colour.eotf_ST2084',
            'colour.models.eotf_ST2084',
        ],
        [
            'colour.eotf_reverse_BT1886',
            'colour.models.eotf_inverse_BT1886',
        ],
        [
            'colour.eotf_reverse_BT2100_HLG',
            'colour.models.eotf_inverse_HLG_BT2100',
        ],
        [
            'colour.eotf_reverse_BT2100_PQ',
            'colour.models.eotf_inverse_PQ_BT2100',
        ],
        [
            'colour.eotf_reverse_ST2084',
            'colour.models.eotf_inverse_ST2084',
        ],
        [
            'colour.eotf_reverse_sRGB',
            'colour.models.eotf_inverse_sRGB',
        ],
        [
            'colour.eotf_sRGB',
            'colour.models.eotf_sRGB',
        ],
        [
            'colour.euclidean_distance',
            'colour.algebra.euclidean_distance',
        ],
        [
            'colour.extend_line_segment',
            'colour.algebra.extend_line_segment',
        ],
        [
            'colour.fill_nan',
            'colour.utilities.fill_nan',
        ],
        [
            'colour.filter_kwargs',
            'colour.utilities.filter_kwargs',
        ],
        [
            'colour.filter_warnings',
            'colour.utilities.filter_warnings',
        ],
        [
            'colour.first_item',
            'colour.utilities.first_item',
        ],
        [
            'colour.handle_numpy_errors',
            'colour.utilities.handle_numpy_errors',
        ],
        [
            'colour.ignore_numpy_errors',
            'colour.utilities.ignore_numpy_errors',
        ],
        [
            'colour.ignore_python_warnings',
            'colour.utilities.ignore_python_warnings',
        ],
        [
            'colour.in_array',
            'colour.utilities.in_array',
        ],
        [
            'colour.intersect_line_segments',
            'colour.algebra.intersect_line_segments',
        ],
        [
            'colour.interval',
            'colour.utilities.interval',
        ],
        [
            'colour.is_identity',
            'colour.algebra.is_identity',
        ],
        [
            'colour.is_integer',
            'colour.utilities.is_integer',
        ],
        [
            'colour.is_iterable',
            'colour.utilities.is_iterable',
        ],
        [
            'colour.is_numeric',
            'colour.utilities.is_numeric',
        ],
        [
            'colour.is_openimageio_installed',
            'colour.utilities.is_openimageio_installed',
        ],
        [
            'colour.is_pandas_installed',
            'colour.utilities.is_pandas_installed',
        ],
        [
            'colour.is_string',
            'colour.utilities.is_string',
        ],
        [
            'colour.is_uniform',
            'colour.utilities.is_uniform',
        ],
        [
            'colour.lagrange_coefficients_ASTME2022',
            'colour.colorimetry.lagrange_coefficients_ASTME2022',
        ],
        [
            'colour.lightness_CIE1976',
            'colour.colorimetry.lightness_CIE1976',
        ],
        [
            'colour.lightness_Fairchild2010',
            'colour.colorimetry.lightness_Fairchild2010',
        ],
        [
            'colour.lightness_Fairchild2011',
            'colour.colorimetry.lightness_Fairchild2011',
        ],
        [
            'colour.lightness_Glasser1958',
            'colour.colorimetry.lightness_Glasser1958',
        ],
        [
            'colour.lightness_Wyszecki1963',
            'colour.colorimetry.lightness_Wyszecki1963',
        ],
        [
            'colour.linear_conversion',
            'colour.utilities.linear_conversion',
        ],
        [
            'colour.log_decoding_ACEScc',
            'colour.models.log_decoding_ACEScc',
        ],
        [
            'colour.log_decoding_ACEScct',
            'colour.models.log_decoding_ACEScct',
        ],
        [
            'colour.log_decoding_ACESproxy',
            'colour.models.log_decoding_ACESproxy',
        ],
        [
            'colour.log_decoding_ALEXALogC',
            'colour.models.log_decoding_ALEXALogC',
        ],
        [
            'colour.log_decoding_CanonLog',
            'colour.models.log_decoding_CanonLog',
        ],
        [
            'colour.log_decoding_CanonLog2',
            'colour.models.log_decoding_CanonLog2',
        ],
        [
            'colour.log_decoding_CanonLog3',
            'colour.models.log_decoding_CanonLog3',
        ],
        [
            'colour.log_decoding_Cineon',
            'colour.models.log_decoding_Cineon',
        ],
        [
            'colour.log_decoding_ERIMMRGB',
            'colour.models.log_decoding_ERIMMRGB',
        ],
        [
            'colour.log_decoding_Log3G10',
            'colour.models.log_decoding_Log3G10',
        ],
        [
            'colour.log_decoding_Log3G12',
            'colour.models.log_decoding_Log3G12',
        ],
        [
            'colour.log_decoding_Panalog',
            'colour.models.log_decoding_Panalog',
        ],
        [
            'colour.log_decoding_PivotedLog',
            'colour.models.log_decoding_PivotedLog',
        ],
        [
            'colour.log_decoding_Protune',
            'colour.models.log_decoding_Protune',
        ],
        [
            'colour.log_decoding_REDLog',
            'colour.models.log_decoding_REDLog',
        ],
        [
            'colour.log_decoding_REDLogFilm',
            'colour.models.log_decoding_REDLogFilm',
        ],
        [
            'colour.log_decoding_SLog',
            'colour.models.log_decoding_SLog',
        ],
        [
            'colour.log_decoding_SLog2',
            'colour.models.log_decoding_SLog2',
        ],
        [
            'colour.log_decoding_SLog3',
            'colour.models.log_decoding_SLog3',
        ],
        [
            'colour.log_decoding_VLog',
            'colour.models.log_decoding_VLog',
        ],
        [
            'colour.log_decoding_ViperLog',
            'colour.models.log_decoding_ViperLog',
        ],
        [
            'colour.log_encoding_ACEScc',
            'colour.models.log_encoding_ACEScc',
        ],
        [
            'colour.log_encoding_ACEScct',
            'colour.models.log_encoding_ACEScct',
        ],
        [
            'colour.log_encoding_ACESproxy',
            'colour.models.log_encoding_ACESproxy',
        ],
        [
            'colour.log_encoding_ALEXALogC',
            'colour.models.log_encoding_ALEXALogC',
        ],
        [
            'colour.log_encoding_CanonLog',
            'colour.models.log_encoding_CanonLog',
        ],
        [
            'colour.log_encoding_CanonLog2',
            'colour.models.log_encoding_CanonLog2',
        ],
        [
            'colour.log_encoding_CanonLog3',
            'colour.models.log_encoding_CanonLog3',
        ],
        [
            'colour.log_encoding_Cineon',
            'colour.models.log_encoding_Cineon',
        ],
        [
            'colour.log_encoding_ERIMMRGB',
            'colour.models.log_encoding_ERIMMRGB',
        ],
        [
            'colour.log_encoding_Log3G10',
            'colour.models.log_encoding_Log3G10',
        ],
        [
            'colour.log_encoding_Log3G12',
            'colour.models.log_encoding_Log3G12',
        ],
        [
            'colour.log_encoding_Panalog',
            'colour.models.log_encoding_Panalog',
        ],
        [
            'colour.log_encoding_PivotedLog',
            'colour.models.log_encoding_PivotedLog',
        ],
        [
            'colour.log_encoding_Protune',
            'colour.models.log_encoding_Protune',
        ],
        [
            'colour.log_encoding_REDLog',
            'colour.models.log_encoding_REDLog',
        ],
        [
            'colour.log_encoding_REDLogFilm',
            'colour.models.log_encoding_REDLogFilm',
        ],
        [
            'colour.log_encoding_SLog',
            'colour.models.log_encoding_SLog',
        ],
        [
            'colour.log_encoding_SLog2',
            'colour.models.log_encoding_SLog2',
        ],
        [
            'colour.log_encoding_SLog3',
            'colour.models.log_encoding_SLog3',
        ],
        [
            'colour.log_encoding_VLog',
            'colour.models.log_encoding_VLog',
        ],
        [
            'colour.luminance_ASTMD153508',
            'colour.colorimetry.luminance_ASTMD1535',
        ],
        [
            'colour.luminance_CIE1976',
            'colour.colorimetry.luminance_CIE1976',
        ],
        [
            'colour.luminance_Fairchild2010',
            'colour.colorimetry.luminance_Fairchild2010',
        ],
        [
            'colour.luminance_Fairchild2011',
            'colour.colorimetry.luminance_Fairchild2011',
        ],
        [
            'colour.luminance_Newhall1943',
            'colour.colorimetry.luminance_Newhall1943',
        ],
        [
            'colour.mesopic_weighting_function',
            'colour.colorimetry.mesopic_weighting_function',
        ],
        [
            'colour.message_box',
            'colour.utilities.message_box',
        ],
        [
            'colour.munsell_value_ASTMD153508',
            'colour.notation.munsell_value_ASTMD1535',
        ],
        [
            'colour.munsell_value_Ladd1955',
            'colour.notation.munsell_value_Ladd1955',
        ],
        [
            'colour.munsell_value_McCamy1987',
            'colour.notation.munsell_value_McCamy1987',
        ],
        [
            'colour.munsell_value_Moon1943',
            'colour.notation.munsell_value_Moon1943',
        ],
        [
            'colour.munsell_value_Munsell1933',
            'colour.notation.munsell_value_Munsell1933',
        ],
        [
            'colour.munsell_value_Priest1920',
            'colour.notation.munsell_value_Priest1920',
        ],
        [
            'colour.munsell_value_Saunderson1944',
            'colour.notation.munsell_value_Saunderson1944',
        ],
        [
            'colour.ndarray_write',
            'colour.utilities.ndarray_write',
        ],
        [
            'colour.normalise_maximum',
            'colour.utilities.normalise_maximum',
        ],
        [
            'colour.normalise_vector',
            'colour.algebra.normalise_vector',
        ],
        [
            'colour.numpy_print_options',
            'colour.utilities.numpy_print_options',
        ],
        [
            'colour.oetf_ARIBSTDB67',
            'colour.models.oetf_ARIBSTDB67',
        ],
        [
            'colour.oetf_BT2020',
            'colour.models.oetf_BT2020',
        ],
        [
            'colour.oetf_BT2100_HLG',
            'colour.models.oetf_HLG_BT2100',
        ],
        [
            'colour.oetf_BT2100_PQ',
            'colour.models.oetf_PQ_BT2100',
        ],
        [
            'colour.oetf_BT601',
            'colour.models.oetf_BT601',
        ],
        [
            'colour.oetf_BT709',
            'colour.models.oetf_BT709',
        ],
        [
            'colour.oetf_DCIP3',
            'colour.models.eotf_inverse_DCIP3',
        ],
        [
            'colour.oetf_DICOMGSDF',
            'colour.models.eotf_inverse_DICOMGSDF',
        ],
        [
            'colour.cctf_encoding_ProPhotoRGB',
            'colour.models.cctf_encoding_ProPhotoRGB',
        ],
        [
            'colour.cctf_encoding_RIMMRGB',
            'colour.models.cctf_encoding_RIMMRGB',
        ],
        [
            'colour.cctf_encoding_ROMMRGB',
            'colour.models.cctf_encoding_ROMMRGB',
        ],
        [
            'colour.oetf_SMPTE240M',
            'colour.models.oetf_SMPTE240M',
        ],
        [
            'colour.oetf_reverse_ARIBSTDB67',
            'colour.models.oetf_inverse_ARIBSTDB67',
        ],
        [
            'colour.oetf_reverse_BT2100_HLG',
            'colour.models.oetf_inverse_HLG_BT2100',
        ],
        [
            'colour.oetf_reverse_BT2100_PQ',
            'colour.models.oetf_inverse_PQ_BT2100',
        ],
        [
            'colour.oetf_reverse_BT601',
            'colour.models.oetf_inverse_BT601',
        ],
        [
            'colour.oetf_reverse_BT709',
            'colour.models.oetf_inverse_BT709',
        ],
        [
            'colour.ootf_BT2100_HLG',
            'colour.models.ootf_HLG_BT2100',
        ],
        [
            'colour.ootf_BT2100_PQ',
            'colour.models.ootf_PQ_BT2100',
        ],
        [
            'colour.ootf_reverse_BT2100_HLG',
            'colour.models.ootf_inverse_HLG_BT2100',
        ],
        [
            'colour.ootf_reverse_BT2100_PQ',
            'colour.models.ootf_inverse_PQ_BT2100',
        ],
        [
            'colour.orient',
            'colour.utilities.orient',
        ],
        [
            'colour.planck_law',
            'colour.colorimetry.planck_law',
        ],
        [
            'colour.polar_to_cartesian',
            'colour.algebra.polar_to_cartesian',
        ],
        [
            'colour.print_numpy_errors',
            'colour.utilities.print_numpy_errors',
        ],
        [
            'colour.raise_numpy_errors',
            'colour.utilities.raise_numpy_errors',
        ],
        [
            'colour.random_triplet_generator',
            'colour.algebra.random_triplet_generator',
        ],
        [
            'colour.rayleigh_optical_depth',
            'colour.phenomena.rayleigh_optical_depth',
        ],
        [
            'colour.reaction_rate_MichealisMenten',
            'colour.biochemistry.reaction_rate_MichealisMenten',
        ],
        [
            'colour.row_as_diagonal',
            'colour.utilities.row_as_diagonal',
        ],
        [
            'colour.sRGB_COLOURSPACE',
            'colour.models.sRGB_COLOURSPACE',
        ],
        [
            'colour.sd_to_XYZ_ASTME30815',
            'colour.colorimetry.sd_to_XYZ_ASTME308',
        ],
        [
            'colour.sd_to_XYZ_integration',
            'colour.colorimetry.sd_to_XYZ_integration',
        ],
        [
            'colour.sd_to_XYZ_tristimulus_weighting_factors_ASTME30815',
            'colour.colorimetry.sd_to_XYZ_tristimulus_weighting_factors_ASTME308',  # noqa
        ],
        [
            'colour.spherical_to_cartesian',
            'colour.algebra.spherical_to_cartesian',
        ],
        [
            'colour.substrate_concentration_MichealisMenten',
            'colour.biochemistry.substrate_concentration_MichealisMenten',
        ],
        [
            'colour.tristimulus_weighting_factors_ASTME2022',
            'colour.colorimetry.tristimulus_weighting_factors_ASTME2022',
        ],
        [
            'colour.tsplit',
            'colour.utilities.tsplit',
        ],
        [
            'colour.tstack',
            'colour.utilities.tstack',
        ],
        [
            'colour.uv_to_CCT_Ohno2013',
            'colour.temperature.uv_to_CCT_Ohno2013',
        ],
        [
            'colour.uv_to_CCT_Robertson1968',
            'colour.temperature.uv_to_CCT_Robertson1968',
        ],
        [
            'colour.warn_numpy_errors',
            'colour.utilities.warn_numpy_errors',
        ],
        [
            'colour.warning',
            'colour.utilities.warning',
        ],
        [
            'colour.whiteness_ASTME313',
            'colour.colorimetry.whiteness_ASTME313',
        ],
        [
            'colour.whiteness_Berger1959',
            'colour.colorimetry.whiteness_Berger1959',
        ],
        [
            'colour.whiteness_CIE2004',
            'colour.colorimetry.whiteness_CIE2004',
        ],
        [
            'colour.whiteness_Ganz1979',
            'colour.colorimetry.whiteness_Ganz1979',
        ],
        [
            'colour.whiteness_Stensby1968',
            'colour.colorimetry.whiteness_Stensby1968',
        ],
        [
            'colour.whiteness_Taube1960',
            'colour.colorimetry.whiteness_Taube1960',
        ],
        [
            'colour.xy_to_CCT_Hernandez1999',
            'colour.temperature.xy_to_CCT_Hernandez1999',
        ],
        [
            'colour.xy_to_CCT_McCamy1992',
            'colour.temperature.xy_to_CCT_McCamy1992',
        ],
        [
            'colour.yellowness_ASTMD1925',
            'colour.colorimetry.yellowness_ASTMD1925',
        ],
        [
            'colour.yellowness_ASTME313',
            'colour.colorimetry.yellowness_ASTME313',
        ],
    ]
}
"""
Defines *colour* package API changes.

API_CHANGES : dict
"""

API_CHANGES.update({
    'ObjectRemoved': [
        'colour.DEFAULT_WAVELENGTH_DECIMALS',
        'colour.ArbitraryPrecisionMapping',
        'colour.SpectralMapping',
    ],
    'ObjectRenamed': [
        [
            'colour.eotf_ARIBSTDB67',
            'colour.models.oetf_inverse_ARIBSTDB67',
        ],
        [
            'colour.eotf_BT709',
            'colour.models.oetf_inverse_BT709',
        ],
        [
            'colour.oetf_BT1886',
            'colour.models.eotf_inverse_BT1886',
        ],
        [
            'colour.eotf_sRGB',
            'colour.models.eotf_sRGB',
        ],
        [
            'colour.ALEXA_WIDE_GAMUT_RGB_COLOURSPACE',
            'colour.models.ALEXA_WIDE_GAMUT_COLOURSPACE',
        ],
        [
            'colour.NTSC_1953_RGB_COLOURSPACE',
            'colour.models.NTSC_1953_COLOURSPACE',
        ],
        [
            'colour.PAL_SECAM_RGB_COLOURSPACE',
            'colour.models.PAL_SECAM_COLOURSPACE',
        ],
        [
            'colour.REC_709_COLOURSPACE',
            'colour.models.BT709_COLOURSPACE',
        ],
        [
            'colour.REC_2020_COLOURSPACE',
            'colour.models.BT2020_COLOURSPACE',
        ],
        [
            'colour.SMPTE_C_RGB_COLOURSPACE',
            'colour.models.SMPTE_240M_COLOURSPACE',
        ],
        [
            'colour.TriSpectralPowerDistribution',
            'colour.MultiSpectralDistributions',
        ],
    ]
})

# v0.3.12
API_CHANGES['ObjectRenamed'] = API_CHANGES['ObjectRenamed'] + [
    [
        'colour.CIE_standard_illuminant_A_function',
        'colour.sd_CIE_standard_illuminant_A',
    ],
    [
        'colour.COLOURCHECKERS_SPDS',
        'colour.COLOURCHECKERS_SDS',
    ],
    [
        'colour.D_illuminant_relative_spd',
        'colour.sd_CIE_illuminant_D_series',
    ],
    [
        'colour.ILLUMINANTS_RELATIVE_SPDS',
        'colour.ILLUMINANTS_SDS',
    ],
    [
        'colour.LIGHT_SOURCES_RELATIVE_SPDS',
        'colour.LIGHT_SOURCES_SDS',
    ],
    [
        'colour.MultiSpectralPowerDistribution',
        'colour.MultiSpectralDistributions',
    ],
    [
        'colour.REFLECTANCE_RECOVERY_METHODS',
        'colour.XYZ_TO_SD_METHODS',
    ],
    [
        'colour.SPECTRAL_TO_XYZ_METHODS',
        'colour.SD_TO_XYZ_METHODS',
    ],
    [
        'colour.SpectralPowerDistribution',
        'colour.SpectralDistribution',
    ],
    [
        'colour.blackbody_spd',
        'colour.sd_blackbody',
    ],
    [
        'colour.constant_spd',
        'colour.sd_constant',
    ],
    [
        'colour.first_order_colour_fit',
        'colour.colour_correction_matrix',
    ],
    [
        'colour.IES_TM2714_Spd',
        'colour.SpectralDistribution_IESTM2714',
    ],
    [
        'colour.function_gamma',
        'colour.gamma_function',
    ],
    [
        'colour.function_linear',
        'colour.linear_function',
    ],
    [
        'colour.mesopic_luminous_efficiency_function',
        'colour.sd_mesopic_luminous_efficiency_function',
    ],
    [
        'colour.ones_spd',
        'colour.sd_ones',
    ],
    [
        'colour.rayleigh_scattering_spd',
        'colour.sd_rayleigh_scattering',
    ],
    [
        'colour.read_spds_from_csv_file',
        'colour.read_sds_from_csv_file',
    ],
    [
        'colour.read_spds_from_xrite_file',
        'colour.read_sds_from_xrite_file',
    ],
    [
        'colour.spectral_to_aces_relative_exposure_values',
        'colour.sd_to_aces_relative_exposure_values',
    ],
    [
        'colour.spectral_to_XYZ',
        'colour.sd_to_XYZ',
    ],
    [
        'colour.write_spds_to_csv_file',
        'colour.write_sds_to_csv_file',
    ],
    [
        'colour.XYZ_to_spectral',
        'colour.XYZ_to_sd',
    ],
    [
        'colour.zeros_spd',
        'colour.sd_zeros',
    ],
]

# v0.3.14
API_CHANGES['ObjectRenamed'] = API_CHANGES['ObjectRenamed'] + [
    [
        'colour.ASTME30815_PRACTISE_SHAPE',
        'colour.ASTME308_PRACTISE_SHAPE',
    ],
    [
        'colour.decoding_cctf',
        'colour.cctf_decoding',
    ],
    [
        'colour.DECODING_CCTFS',
        'colour.CCTF_DECODINGS',
    ],
    [
        'colour.encoding_cctf',
        'colour.cctf_encoding',
    ],
    [
        'colour.ENCODING_CCTFS',
        'colour.CCTF_ENCODINGS',
    ],
    [
        'colour.EOTFS_REVERSE',
        'colour.EOTF_INVERSES',
    ],
    [
        'colour.eotf_reverse',
        'colour.eotf_inverse',
    ],
    [
        'colour.log_decoding_curve',
        'colour.log_decoding',
    ],
    [
        'colour.LOG_DECODING_CURVES',
        'colour.LOG_DECODINGS',
    ],
    [
        'colour.log_encoding_curve',
        'colour.log_encoding',
    ],
    [
        'colour.LOG_ENCODING_CURVES',
        'colour.LOG_ENCODINGS',
    ],
    [
        'colour.OETFS_REVERSE',
        'colour.OETF_INVERSES',
    ],
    [
        'colour.oetf_reverse',
        'colour.oetf_inverse',
    ],
    [
        'colour.OOTFS_REVERSE',
        'colour.OOTF_INVERSES',
    ],
    [
        'colour.ootf_reverse',
        'colour.ootf_inverse',
    ],
    [
        'colour.MultiSpectralDistribution',
        'colour.MultiSpectralDistributions',
    ],
]

if not is_documentation_building():
    sys.modules['colour'] = colour(sys.modules['colour'],
                                   build_API_changes(API_CHANGES))

    del ModuleAPI, is_documentation_building, build_API_changes, sys