Skip to content

Commit

Permalink
Updates to Dimension Reduction documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
mds2120 committed Apr 5, 2022
1 parent 0fad6b1 commit 130fd97
Show file tree
Hide file tree
Showing 9 changed files with 140 additions and 74 deletions.
Original file line number Diff line number Diff line change
@@ -1,23 +1,33 @@
Interpolation
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
:py:mod:`UQpy` offers the capability to interpolate points on the Grassmann :math:`\mathcal{G}(p,n)`. Consider we have a set of
:math:`n+1` points :math:`(t_0, \mathbf{X}_0), ..., (t_n, \mathbf{X}_n)`, with :math:`t_0 <...<t_n` and
:py:mod:`UQpy` offers the capability to interpolate points on the Grassmann :math:`\mathcal{G}(p,n)`. Consider we have a
set of :math:`n+1` points :math:`(t_0, \mathbf{X}_0), ..., (t_n, \mathbf{X}_n)`, with :math:`t_0 <...<t_n` and
:math:`\mathbf{X}_k \in \mathbb{R}^{p \times n}`, and we want to find
a function :math:`p(x)` for which :math:`p(t_k)=\mathbf{X}_k` for :math:`k=0,..,n`. In this setting,
a function :math:`p(x)` for which :math:`p(t_k)=\mathbf{X}_k` for :math:`k=0,..,n` where
:math:`x` is a continuous independent variable and :math:`t_k` are called the nodes (or coordinates) of the interpolant.
However, since the Grassmann manifold has a nonlinear structure, interpolation can only be performed on the tangent space
which is a flat space. To this end, the steps required to interpolate a point on :math:`\mathcal{G}(p,n)` the are the
following:
However, since the Grassmann manifold has a nonlinear structure, interpolation can only be performed on the tangent
space, which is a flat inner-product space. Therefore the following steps are required to interpolate on
:math:`\mathcal{G}(p,n)`:

1. Calculate the Karcher mean of the given points on the manifold.
2. Project all points onto the tangent space with origin the Karcher mean.
2. Project all points onto the tangent space with origin at the Karcher mean.
3. Perform the interpolation on the tangent space using the available methods.
4. Map the interpolated point back onto the manifold.

The :class:`.GrassmannInterpolation` class provides a framework to perform these steps. To use this
class we need to import it first
class we need to import it as follows:

>>> from UQpy.dimension_reduction.grassmann_manifold.GrassmannInterpolation import GrassmannInterpolation

We must then instantiate a :class:`.GrassmannInterpolation` object and then invoke the :py:meth:`.interpolate_manifold`
method as:

>>> X = GrassmannInterpolation()
>>> Y = X.interpolate_manifold(point)


Methods
~~~~~~~~~~~~~~~~~~~

.. autoclass:: UQpy.dimension_reduction.GrassmannInterpolation
:members:
83 changes: 60 additions & 23 deletions docs/source/dimension_reduction/grassmann/grassmann_operations.rst
Original file line number Diff line number Diff line change
@@ -1,17 +1,28 @@
Operations
Grassmann Operations
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

:py:mod:`UQpy` supports several operations on the Grassmann manifold. These operations are defined as methods of the
:class:`.GrassmannOperations` class described herein.

.. autoclass:: UQpy.dimension_reduction.grassmann_manifold.GrassmannOperations

Exponential mapping
Methods
~~~~~~~~~~~~~~~~~~~~~~
The following sections introduce the methods available in the :class:`.GrassmannOperations` class with a brief
introduction to their theory and their specifications in :py:mod:`UQpy`.

Exponential Map
~~~~~~~~~~~~~~~~~~~~~~

For point :math:`\mathbf{X}` we can define the tangent space :math:`\mathcal{T}_{\mathbf{X}, \mathcal{G}(p,n)}` as the set of all matrices :math:`\mathbf{\Gamma}` at :math:`\mathbf{X}` such as
For point :math:`\mathbf{X}` on the Grassmann manifold :math:`\mathcal{G}(p,n)`, we can define the tangent space
:math:`\mathcal{T}_{\mathbf{X}, \mathcal{G}(p,n)}` as the set of all matrices :math:`\mathbf{\Gamma}` such that

.. math:: \mathcal{T}_{\mathbf{X}, \mathcal{G}(p,n)} = \{\mathbf{\Gamma} \in \mathbb{R}^{n \times p} : \mathbf{\Gamma}^T\mathbf{X}=\mathbf{0}\}
.. math:: \mathcal{T}_{\mathbf{X}, \mathcal{G}(p,n)} = \{\mathbf{\Gamma} \in \mathbb{R}^{n \times p} :\mathbf{\Gamma}^T\mathbf{X}=\mathbf{0}\}


Consider two points :math:`\mathbf{X}` and :math:`\mathbf{Y}` on :math:`\mathcal{G}(p, n)` and the tangent space :math:`\mathcal{T}_{\mathbf{X}, \mathcal{G}(p,n)}` at :math:`\mathbf{X}`. The geodesic, which refers to the shortest curve on the manifold connecting the two points, is defined as
Consider two points :math:`\mathbf{X}` and :math:`\mathbf{Y}` on :math:`\mathcal{G}(p, n)` and the tangent space
:math:`\mathcal{T}_{\mathbf{X}, \mathcal{G}(p,n)}` at :math:`\mathbf{X}`. The geodesic, which refers to the shortest
curve on the manifold connecting the two points, is defined as

.. math:: \mathbf{\Gamma} = \mathbf{U}\mathbf{S}\mathbf{V}^T

Expand All @@ -20,80 +31,106 @@ Consider two points :math:`\mathbf{X}` and :math:`\mathbf{Y}` on :math:`\mathcal
where :math:`\mathbf{\Phi}(0)=\mathbf{X}` and :math:`\mathbf{\Phi}(1)=\mathbf{Y}`.


The exponential map, denoted as :math:`\mathcal{T}_{\mathbf{X}, \mathcal{G}(p,n)} \rightarrow \mathcal{G}(p, n)`, maps a tangent vector :math:`\mathbf{\Gamma} \in \mathcal{T}_{\mathbf{X}, \mathcal{G}(p,n)}` to the endpoint :math:`\mathbf{Y}=\Phi(1)` of the unique geodesic :math:`\Phi` that emanates from :math:`\mathbf{X}` in the direction :math:`\mathbf{\Gamma}`.
The exponential map, denoted as
:math:`\mathrm{exp}_{\mathbf{X}}(\mathbf{\Gamma}): \mathcal{T}_{\mathbf{X}, \mathcal{G}(p,n)} \rightarrow \mathcal{G}(p, n)`, maps a tangent vector :math:`\mathbf{\Gamma} \in \mathcal{T}_{\mathbf{X}, \mathcal{G}(p,n)}` to the endpoint :math:`\mathbf{Y}=\Phi(1)` of the unique geodesic :math:`\Phi` that emanates from :math:`\mathbf{X}` in the direction :math:`\mathbf{\Gamma}`.


.. math:: \mathrm{exp}_{\mathbf{X}}(\mathbf{\Gamma})\equiv\mathbf{Y}

.. math:: \mathbf{Y} = \mathrm{exp}_{\mathbf{X}}(\mathbf{U}\mathbf{S}\mathbf{V}^T) = \mathbf{X}\mathbf{V}\mathrm{cos}\left(\mathbf{S}\right)\mathbf{Q}^T+\mathbf{U}\mathrm{sin}\left(\mathbf{S}\right)\mathbf{Q}^T

The exponential map is implemented in :py:mod:`UQpy` through the static :meth:`.exp_map` method.

In order to use the method :meth:`.exp_map` one needs to import the :class:`.Grassmann` class from the :mod:`UQpy.dimension_reduction.grassmann_manifold` module
To use the :meth:`.exp_map` method, one needs to import the :class:`.GrassmannOperations` class from the
:mod:`UQpy.dimension_reduction.grassmann_manifold` module as follows:

>>> from UQpy.dimension_reduction.grassmann_manifold import GrassmannOperations

It can then be used as follows:

>>> GrassmannOperations.exp_map()

Since :meth:`.exp_map` is a static method, it does not require instantiation of the class.
Since :meth:`.exp_map` is a static method, it does not require instantiation of the :class:`.GrassmannOperations` class.

.. automethod:: UQpy.dimension_reduction.grassmann_manifold.GrassmannOperations.exp_map




Logarithmic map
Logarithmic Map
~~~~~~~~~~~~~~~~~~~~~~

The logarithmic map, denoted as :math:`\mathcal{G}(p, n) \rightarrow \mathcal{T}_{\mathbf{X}\mathcal{G}(p,n)}` maps the endpoint :math:`\mathbf{Y}=\Phi(1)` of the unique geodesic :math:`\Phi` that emanates from :math:`\mathbf{X}` to a tangent vector :math:`\mathbf{\Gamma} \in \mathcal{T}_{\mathbf{X}, \mathcal{G}(p,n)}`.
The logarithmic map, denoted as
:math:`\mathrm{log}_\mathbf{X}(\mathbf{Y}):\mathcal{G}(p, n) \rightarrow \mathcal{T}_{\mathbf{X}\mathcal{G}(p,n)}` maps
the endpoint :math:`\mathbf{Y}=\Phi(1)` of the unique geodesic :math:`\Phi` that emanates from :math:`\mathbf{X}` to a tangent vector :math:`\mathbf{\Gamma} \in \mathcal{T}_{\mathbf{X}, \mathcal{G}(p,n)}`.


.. math:: \mathrm{log}_\mathbf{X}(\mathbf{Y})\equiv \mathbf{\Gamma} = \mathbf{U}\mathrm{tan}^{-1}\left(\mathbf{S}\right)\mathbf{V}^T

In order to use the method :meth:`.log_map` one needs to import the :class:`.Grassmann` class from the :mod:`UQpy.dimension_reduction.grassmann_manifold` module
where :math:`\mathbf{U}, \mathbf{S}, \mathbf{V}` are define as in the exponential map above.

To use the :meth:`.log_map` method, one needs to import the :class:`.GrassmannOperations` class from the
:mod:`UQpy.dimension_reduction.grassmann_manifold` module as follows:

>>> from UQpy.dimension_reduction.grassmann_manifold import GrassmannOperations

It can then be used as follows:

>>> GrassmannOperations.log_map()


Since :meth:`.log_map` is a static method, it does not require instantiation of the class.
Since :meth:`.log_map` is a static method, it does not require instantiation of the :class:`.GrassmannOperations` class.

.. automethod:: UQpy.dimension_reduction.grassmann_manifold.GrassmannOperations.log_map

Karcher mean
~~~~~~~~~~~~~~~~~~~~~~

For a set of points :math:`\{\mathbf{X}_i\}_{i=1}^N` on :math:`\mathcal{G}(p,n)` the Karcher mean is defined as the solution of the following minimization problem:
For a set of points :math:`\{\mathbf{X}_i\}_{i=1}^N` on :math:`\mathcal{G}(p,n)` the Karcher mean is defined as the
solution of the following minimization problem:

.. math:: \mu = \arg_{\mathbf{Y}} \mathrm{min}(\frac{1}{N}\sum_{i=1}^N d(\mathbf{X}_i, \mathbf{Y})^2)
.. math:: \mu = \arg_{\mathbf{Y}} \mathrm{min}\left(\frac{1}{N}\sum_{i=1}^N d(\mathbf{X}_i, \mathbf{Y})^2\right)

where :math:`d(\cdot)` is a Grassmann distance metric and :math:`\mathbf{Y}` is a reference point on :math:`\mathcal{G}(p,n)`.
where :math:`d(\cdot)` is a Grassmann distance measure and :math:`\mathbf{Y}` is a reference point on :math:`\mathcal{G}(p,n)`.

In order to use the method :meth:`.karcher_mean` one needs to import the :class:`.Grassmann` class from the :mod:`UQpy.dimension_reduction.grassmann_manifold` module
To use the :meth:`.karcher_mean` method, one needs to import the :class:`.GrassmannOperations` class from the
:mod:`UQpy.dimension_reduction.grassmann_manifold` module as follows:

>>> from UQpy.dimension_reduction.grassmann_manifold import GrassmannOperations

It can then be used as follows:

>>> Grassmann.karcher_mean()

Since :meth:`.karcher_mean` is a static method, it does not require instantiation of the class.
Since :meth:`.karcher_mean` is a static method, it does not require instantiation of the :class:`.GrassmannOperations`
class.

.. automethod:: UQpy.dimension_reduction.grassmann_manifold.GrassmannOperations.karcher_mean

:mod:`UQpy` offers two methods for solving this optimization, the :class:`.GradientDescent` and the :class:`.StochasticGradientDescent`.
:mod:`UQpy` offers two methods for solving this optimization, the :class:`.GradientDescent` and the
:class:`.StochasticGradientDescent`. Both are implemented as private methods of the :class:`.GrassmannOperations`
class.


Frechet variance
~~~~~~~~~~~~~~~~~~~~~~

For a set of points :math:`\{\mathbf{X}_i\}_{i=1}^N` on :math:`\mathcal{G}(p,n)` the Frechet variance is defined as the solution of the following minimization problem:
For a set of points :math:`\{\mathbf{X}_i\}_{i=1}^N` on :math:`\mathcal{G}(p,n)` the Frechet variance is defined as:

.. math:: \sigma_{f}^2 = \mathrm{min}(\frac{1}{N}\sum_{i=1}^N d(\mathbf{X}_i, \mu)^2)
.. math:: \sigma_{f}^2 = \frac{1}{N}\sum_{i=1}^N d(\mathbf{X}_i, \mu)^2

where :math:`d(\cdot)` is a Grassmann distance metric and :math:`\mu` the Karcher mean of set of points :math:`\{\mathbf{X}_i\}_{i=1}^N` on :math:`\mathcal{G}(p,n)`.
where :math:`d(\cdot)` is a Grassmann distance measure and :math:`\mu` is the Karcher mean of set of points :math:`\{\mathbf{X}_i\}_{i=1}^N` on :math:`\mathcal{G}(p,n)`.

In order to use the method :meth:`.frechet_variance` one needs to import the :class:`.Grassmann` class from the :mod:`UQpy.dimension_reduction.grassmann_manifold` module
To use the :meth:`.frechet_variance` method, one needs to import the :class:`.GrassmannOperations` class from the
:mod:`UQpy.dimension_reduction.grassmann_manifold` module as follows:

>>> from UQpy.dimension_reduction.grassmann_manifold import GrassmannOperations

It can then be used as follows:

>>> GrassmannOperations.frechet_variance()

Since :meth:`.frechet_variance` is a static method, it does not require instantiation of the class.
Since :meth:`.frechet_variance` is a static method, it does not require instantiation of the
:class:`.GrassmannOperations` class.

.. automethod:: UQpy.dimension_reduction.grassmann_manifold.GrassmannOperations.frechet_variance
8 changes: 4 additions & 4 deletions docs/source/dimension_reduction/grassmann/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ the Grassmann manifold.
:maxdepth: 1
:caption: Methods

Projections <manifold_projections>
Operations <grassmann_operations>
Interpolation <grassmann_interpolation>
Manifold Examples <../../auto_examples/dimension_reduction/grassmann/index>
Grassmann Projections <manifold_projections>
Grassmann Operations <grassmann_operations>
Grassmann Interpolation <grassmann_interpolation>
Grassmann Examples <../../auto_examples/dimension_reduction/grassmann/index>
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ The :class:`.GrassmannProjection` class is imported using the following command:

>>> from UQpy.dimension_reduction.grassmann_manifold.projections.baseclass.GrassmannProjection import GrassmannProjection

The user may create a new Grassmann projection method by subclassing :class:`.GrassmannProjection`. Any such class
must create points with type :class:`.GrassmannPoint`.

SVD Projection
~~~~~~~~~~~~~~~~~~~~~~

Expand Down
18 changes: 18 additions & 0 deletions docs/source/utilities/grassmann_point.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
Grassmann Point
-----------------------------------

The :py:mod:`UQpy` class :class:`.GrassmannPoint` offers a way to check whether a data point, given as a matrix
:math:`\mathbf{X} \in \mathbb{R}^{n \times p}`, belongs on the corresponding Grassmann manifold. The class takes, as
input, an orthonormal 2d :class:`.numpy.ndarray` i.e., :math:`\text{shape}(\mathbf{X})=(p, n)`, and checks if this matrix
is an orthonormal basis that lies with :math:`\mathbf{X}' \mathbf{X} = \mathbf{I}` on the Grassmann manifold. If it is,
then it creates the corresponding :class:`.GrassmannPoint` object.

To use the :class:`.GrassmannPoint` class one needs to first import it by

>>> from UQpy.utilities.GrassmannPoint import GrassmannPoint

To create an object of type :class:`.GrassmannPoint`

>>> X = GrassmannPoint(X)

.. autoclass:: UQpy.utilities.GrassmannPoint
19 changes: 4 additions & 15 deletions docs/source/utilities/index.rst
Original file line number Diff line number Diff line change
@@ -1,24 +1,13 @@
Utilities
================

The :py:mod:`.Utilities` module contains a set of classes that support operations in :py:mod:`UQpy` that
may be useful across several modules. These utilities include the following:

.. toctree::
:maxdepth: 1
:caption: Auxiliary functionalities

Distances <distances/index>
Kernels <kernels/index>
GrassmannPoint <grassmann_point.rst>

Grassmann Point
^^^^^^^^^^^^^^^

The :py:mod:`UQpy` class :class:`.GrassmannPoint` offers a way to check that a data point, given as a matrix :math:`\mathbf{X} \in \mathbb{R}^{n \times p}`, belongs on the corresponding Grassmann manifold. To this end, the user needs to create an object of type :class:`.GrassmannPoint`
that will check that the point is given as an orthonormal 2-d numpy.array, i.e., :math:`\text{shape}(\mathbf{X})=(p, n)` and :math:`\mathbf{X}' \mathbf{X} = \mathbf{I}`.
In order to use the class :class:`.GrassmannPoint` one needs to import it

>>> from UQpy.utilities.GrassmannPoint import GrassmannPoint

To create an object of type :class:`.GrassmannPoint`

>>> X = GrassmannPoint(X)

.. autoclass:: UQpy.utilities.GrassmannPoint
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,13 @@ def __init__(self, interpolation_method: Union[Surrogate, callable, None],
"""
A class to perform interpolation of points on the Grassmann manifold.
:param interpolation_method: Type of interpolation.
:param manifold_data: Data on the Grassmann manifold.
:param optimization_method: Optimization method for calculating the Karcher mean.
:param interpolation_method: Type of interpolation to perform. This may be specified as a :class:`Surrogate`
object or a callable function. If :any:`None`, then multi-linear interpolation is performed.
:param manifold_data: Data points on the Grassmann manifold.
:param optimization_method: Optimization method for calculating the Karcher mean. See
:py:meth:`.GrassmannOperations.karcher_mean`.
:param coordinates: Nodes of the interpolant.
:param distance: Distance metric.
:param distance: Distance measure.
"""
self.interpolation_method = interpolation_method

Expand Down Expand Up @@ -54,8 +56,8 @@ def __init__(self, interpolation_method: Union[Surrogate, callable, None],

def interpolate_manifold(self, point: np.ndarray):
"""
:param point: Point to interpolate.
:return: Interpolated point
:param point: Point at which to interpolate.
:return: Interpolated point on the Grassmann manifold.
"""

shape_ref = np.shape(self.tangent_points[0])
Expand Down
Loading

0 comments on commit 130fd97

Please sign in to comment.