astro py:docs

- Index
- Modules

### Navigation

- Astropy v1.1.1 »
- Module code »

# Source code for astropy.modeling.mappings

    """
    Special models useful for complex compound models where control is needed over
    which outputs from a source model are mapped to which inputs of a target model.
    """

    from .core import Model

    __all__ = ['Mapping', 'Identity']

    class Mapping(Model):
        """
        Allows inputs to be reordered, duplicated or dropped.

        Parameters
        ----------
        mapping : tuple
            A tuple of integers representing indices of the inputs to this model
            to return and in what order to return them.  See
            :ref:`compound-model-mappings` for more details.
        n_inputs : int
            Number of inputs; if `None` (default) then ``max(mapping) + 1`` is
            used (i.e. the highest input index used in the mapping).
        name : str, optional
            A human-friendly name associated with this model instance
            (particularly useful for identifying the individual components of a
            compound model).
        meta : dict-like
            Free-form metadata to associate with this model.

        Raises
        ------
        TypeError
            Raised when number of inputs is less that ``max(mapping)``.

        Examples
        --------

        >>> from astropy.modeling.models import Polynomial2D, Shift, Mapping
        >>> poly1 = Polynomial2D(1, c0_0=1, c1_0=2, c0_1=3)
        >>> poly2 = Polynomial2D(1, c0_0=1, c1_0=2.4, c0_1=2.1)
        >>> model = (Shift(1) & Shift(2)) | Mapping((0, 1, 0, 1)) | (poly1 & poly2)
        >>> model(1, 2)  # doctest: +FLOAT_CMP
        (17.0, 14.2)
        """

        def __init__(self, mapping, n_inputs=None, name=None, meta=None):
            if n_inputs is None:
                self._inputs = tuple('x' + str(idx)
                                     for idx in range(max(mapping) + 1))
            else:
                self._inputs = tuple('x' + str(idx)
                                     for idx in range(n_inputs))
            self._outputs = tuple('x' + str(idx) for idx in range(len(mapping)))
            self._mapping = mapping
            super(Mapping, self).__init__(name=name, meta=meta)

        @property
        def inputs(self):
            """
            The name(s) of the input variable(s) on which a model is evaluated.
            """

            return self._inputs

        @property
        def outputs(self):
            """The name(s) of the output(s) of the model."""

            return self._outputs

        @property
        def mapping(self):
            """Integers representing indices of the inputs."""

            return self._mapping

        def __repr__(self):
            if self.name is None:
                return '<Mapping({0})>'.format(self.mapping)
            else:
                return '<Mapping({0}, name={1})>'.format(self.mapping, self.name)

        def evaluate(self, *args):
            if len(args) != self.n_inputs:
                name = self.name if self.name is not None else "Mapping"

                raise TypeError('{0} expects {1} inputs; got {2}'.format(
                    name, self.n_inputs, len(args)))

            result = tuple(args[idx] for idx in self._mapping)

            if self.n_outputs == 1:
                return result[0]

            return result

        @property
        def inverse(self):
            """
            A `Mapping` representing the inverse of the current mapping.

            Raises
            ------
            `NotImplementedError`
                An inverse does no exist on mappings that drop some of its inputs
                (there is then no way to reconstruct the inputs that were dropped).
            """

            try:
                mapping = tuple(self.mapping.index(idx)
                                for idx in range(self.n_inputs))
            except ValueError:
                raise NotImplementedError(
                    "Mappings such as {0} that drop one or more of their inputs "
                    "are not invertible at this time.".format(self.mapping))

            inv = self.__class__(mapping)
            inv._inputs = self._outputs
            inv._outputs = self._inputs
            return inv

    class Identity(Mapping):
        """
        Returns inputs unchanged.

        This class is useful in compound models when some of the inputs must be
        passed unchanged to the next model.

        Parameters
        ----------
        n_inputs : int
            Specifies the number of inputs this identity model accepts.
        name : str, optional
            A human-friendly name associated with this model instance
            (particularly useful for identifying the individual components of a
            compound model).
        meta : dict-like
            Free-form metadata to associate with this model.

        Examples
        --------

        Transform ``(x, y)`` by a shift in x, followed by scaling the two inputs::

            >>> from astropy.modeling.models import (Polynomial1D, Shift, Scale,
            ...                                      Identity)
            >>> model = (Shift(1) & Identity(1)) | Scale(1.2) & Scale(2)
            >>> model(1,1)  # doctest: +FLOAT_CMP
            (2.4, 2.0)
            >>> model.inverse(2.4, 2) # doctest: +FLOAT_CMP
            (1.0, 1.0)
        """

        def __init__(self, n_inputs, name=None, meta=None):
            mapping = tuple(range(n_inputs))
            super(Identity, self).__init__(mapping, name=name, meta=meta)

        def __repr__(self):
            if self.name is None:
                return '<Identity({0})>'.format(self.n_inputs)
            else:
                return '<Identity({0}, name={1})>'.format(self.n_inputs, self.name)

        @property
        def inverse(self):
            """
            The inverse transformation.

            In this case of `Identity`, ``self.inverse is self``.
            """

            return self