Skip to content

Commit

Permalink
Final MDS updates to kernels
Browse files Browse the repository at this point in the history
  • Loading branch information
mds2120 committed Apr 7, 2022
1 parent 7ae39e8 commit 164f072
Show file tree
Hide file tree
Showing 8 changed files with 77 additions and 56 deletions.
2 changes: 1 addition & 1 deletion docs/source/utilities/kernels/euclidean_kernels.rst
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ The :class:`.GaussianKernel` class is imported using the following command:

>>> from UQpy.utilities.kernels.GaussianKernel import GaussianKernel

One can use the following to instantiate the class :class:`.GaussianKernel`
One can use the following to instantiate the :class:`.GaussianKernel` class.

Methods
~~~~~~~~~
Expand Down
66 changes: 25 additions & 41 deletions docs/source/utilities/kernels/grassmann_kernels.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,15 @@ Grassmannian Kernels
-----------------------------------

In several applications the use of subspaces is essential to describe the underlying geometry of data. However, it is
well-known that subspaces do not follow the Euclidean geometry because they lie on the Grassmann manifold.Therefore,
working with subspaces requires the definition of an embedding structure of the Grassmann manifold into a Hilbert
space. Thus, using positive definite kernels is studied as a solution to this problem. In this regard, a real-valued
positive definite kernel is defined as a symmetric function :math:`k:\mathcal{X}\times \mathcal{X} \rightarrow \mathbb{R}`
if and only if :math:`\sum^n_{I,j=1}c_i c_j k(x_i,x_j) \leq 0` for :math:`n \in \mathbb{N}`, :math:`x_i \in \mathcal{X}`
and :math:`c_i \in \mathbb{R}`. On the Grassmann manifold a kernel is defined as a well-defined and positive definite
function :math:`k:\mathcal{G}(p,n)\times \mathcal{G}(p,n) \rightarrow \mathbb{R}` :cite:`kernels_1`, :cite:`kernels_2`. A Grassmann kernel is a
well-defined positive definite function that embeds the Grassmannian into a Hilbert space. :py:mod:`UQpy` introduces
two Grassmann kernels have been proposed in literature and have demonstrated the potential for subspace-based learning
problems.

Grassmannian Kernel
well-known that sets of subspaces do not follow Euclidean geometry. Instead they have a Reimannian structure and lie on
a Grassmann manifold. Grassmannian kernels can be used to embed the structure of the Grassmann manifold into a Hilbert
space. On the Grassmann manifold, a kernel is defined as a positive definite function
:math:`k:\mathcal{G}(p,n)\times \mathcal{G}(p,n) \rightarrow \mathbb{R}` :cite:`kernels_1`, :cite:`kernels_2`.

:py:mod:`UQpy` includes Grassmannian kernels through the :class:`.GrassmannianKernel` parent class,
with specific kernels included as subclasses. This is described in the following.

Grassmannian Kernels
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

The :class:`.GrassmannianKernel` class is imported using the following command:
Expand All @@ -23,14 +20,20 @@ The :class:`.GrassmannianKernel` class is imported using the following command:
.. autoclass:: UQpy.utilities.kernels.baseclass.GrassmannianKernel
:members: calculate_kernel_matrix

Projection
Projection Kernel
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

The projection kernel is defined as:

.. math:: k_p(\mathbf{X}_i, \mathbf{X}_j) = ||\mathbf{X}_i^T\mathbf{X}_j||_F^2

where :math:`\mathbf{X}_i, \mathbf{X}_j \in \mathcal{G}(p,n)`

The :class:`.ProjectionKernel` class is imported using the following command:

>>> from UQpy.utilities.kernels.ProjectionKernel import ProjectionKernel

One can use the following command to instantiate the class :class:`.ProjectionKernel`
One can use the following command to instantiate the :class:`.ProjectionKernel` class.

.. autoclass:: UQpy.utilities.kernels.ProjectionKernel
:members:
Expand All @@ -39,43 +42,24 @@ One can use the following command to instantiate the class :class:`.ProjectionKe



Binet-Cauchy
Binet-Cauchy Kernel
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

The Binet-Cauchy Kernel is defined as:

.. math:: k_p(\mathbf{X}_i, \mathbf{X}_j) = \det(\mathbf{X}_i^T\mathbf{X}_j)^2

where :math:`\mathbf{X}_i, \mathbf{X}_j \in \mathcal{G}(p,n)`

The :class:`.BinetCauchyKernel` class is imported using the following command:

>>> from UQpy.utilities.kernels.BinetCauchyKernel import BinetCauchyKernel

One can use the following command to instantiate the class :class:`.BinetCauchyKernel`
One can use the following command to instantiate the :class:`.BinetCauchyKernel` class.

.. autoclass:: UQpy.utilities.kernels.BinetCauchyKernel
:members:

.. autoattribute:: UQpy.utilities.kernels.BinetCauchyKernel.kernel_matrix


Calculate Svd Projection SUM or PRODUCT kernel
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

>>> D1 = 6
>>> r0 = 2 # rank sample 0
>>> r1 = 3 # rank sample 1
>>> r2 = 4 # rank sample 2
>>> r3 = 3 # rank sample 2
>>>
>>> Sol0 = np.dot(np.random.rand(D1, r0), np.random.rand(r0, D1))
>>> Sol1 = np.dot(np.random.rand(D1, r1), np.random.rand(r1, D1))
>>> Sol2 = np.dot(np.random.rand(D1, r2), np.random.rand(r2, D1))
>>> Sol3 = np.dot(np.random.rand(D1, r3), np.random.rand(r3, D1))
>>>
>>> # Creating a list of solutions.
>>> Solutions = [Sol0, Sol1, Sol2, Sol3]
>>> from UQpy.dimension_reduction.grassmann_manifold.GrassmannOperations import Grassmann
>>> manifold_projection = SvdProjection(Solutions, p="max")
>>> kernel = ProjectionKernel()
>>>
>>> kernel_psi = kernel.calculate_kernel_matrix(manifold_projection.u)
>>> kernel_phi = kernel.calculate_kernel_matrix(manifold_projection.v)
>>>
>>> sum_kernel = kernel_psi + kernel_phi
>>> product_kernel = kernel_psi * kernel_phi
6 changes: 6 additions & 0 deletions docs/source/utilities/kernels/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@ Kernels

A collection of symmetric positive-definite kernel functions in the Euclidean space and on the Grassmann manifold.

A real-valued positive definite kernel is defined as a symmetric function
:math:`k:\mathcal{X}\times \mathcal{X} \rightarrow \mathbb{R}`
where :math:`\sum^n_{i,j=1}c_i c_j k(x_i,x_j) \leq 0` for :math:`n \in \mathbb{N}`, :math:`x_i \in \mathcal{X}`
and :math:`c_i \in \mathbb{R}`.

Each kernel function in :py:mod:`UQpy` is defined as a subclass of the :class:`.Kernel` class. The :class:`.Kernel` has
two further subclasses for Euclidean kernels (:class:`.EuclideanKernel`) and Grassmannian kernels
(:class:`.GrassmannianKernel`). Individual kernels, depending on their type, are defined as subclasses of these.
Expand All @@ -27,3 +32,4 @@ The :class:`Kernel` class has subclasses for the following types of kernels:

Euclidean Kernels <euclidean_kernels>
Grassmannian Kernels <grassmann_kernels>
Sum and Product Kernels <sum_product_kernels>
39 changes: 39 additions & 0 deletions docs/source/utilities/kernels/sum_product_kernels.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
Sum and Product Kernels
-----------------------------------

Sum and product kernels defined as

.. math:: k_{\text{sum}}(x_i, x_j) = k_1(x_i, x_j) + k_2(x_i, x_j)

and

.. math:: k_{\text{prod}}(x_i, x_j) = k_1(x_i, x_j) \cdot k_2(x_i, x_j)

respectively can be easily computed by simply summing or multiply the kernel matrices as illustrated in the following
example.

Example sum and product Grassmannian kernels
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

>>> D1 = 6
>>> r0 = 2 # rank sample 0
>>> r1 = 3 # rank sample 1
>>> r2 = 4 # rank sample 2
>>> r3 = 3 # rank sample 2
>>>
>>> Sol0 = np.dot(np.random.rand(D1, r0), np.random.rand(r0, D1))
>>> Sol1 = np.dot(np.random.rand(D1, r1), np.random.rand(r1, D1))
>>> Sol2 = np.dot(np.random.rand(D1, r2), np.random.rand(r2, D1))
>>> Sol3 = np.dot(np.random.rand(D1, r3), np.random.rand(r3, D1))
>>>
>>> # Creating a list of solutions.
>>> Solutions = [Sol0, Sol1, Sol2, Sol3]
>>> from UQpy.dimension_reduction.grassmann_manifold.GrassmannOperations import Grassmann
>>> manifold_projection = SvdProjection(Solutions, p="max")
>>> kernel = ProjectionKernel()
>>>
>>> kernel_psi = kernel.calculate_kernel_matrix(manifold_projection.u)
>>> kernel_phi = kernel.calculate_kernel_matrix(manifold_projection.v)
>>>
>>> sum_kernel = kernel_psi + kernel_phi
>>> product_kernel = kernel_psi * kernel_phi
6 changes: 1 addition & 5 deletions src/UQpy/utilities/kernels/BinetCauchyKernel.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,7 @@

class BinetCauchyKernel(GrassmannianKernel):
"""
A class to calculate the Binet-Cauchy kernel defined as:
.. math::
k_p(x_j, x_i) = det(x_j'\cdot xj)^2
A class to calculate the Binet-Cauchy kernel.
"""
def apply_method(self, points):
Expand Down
2 changes: 1 addition & 1 deletion src/UQpy/utilities/kernels/GaussianKernel.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ def kernel_entry(self, xi: Numpy2DFloatArray, xj: Numpy2DFloatArray):
d = pdist(np.array([xi, xj]), "sqeuclidean")
else:
d = np.linalg.norm(xi-xj, 'fro') ** 2
return np.exp(-d / (4*self.epsilon))
return np.exp(-d / (2*self.epsilon**2))

def optimize_parameters(self, data: np.ndarray, tolerance: float,
n_nearest_neighbors: int,
Expand Down
6 changes: 1 addition & 5 deletions src/UQpy/utilities/kernels/ProjectionKernel.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,7 @@

class ProjectionKernel(GrassmannianKernel):
"""
A class to calculate the Projection kernel defined as:
.. math::
k_p(x_j, x_i) = (||x_j'\cdot xj||_F)^2
A class to calculate the Projection kernel
"""
def apply_method(self, points):
Expand Down
6 changes: 3 additions & 3 deletions src/UQpy/utilities/kernels/baseclass/GrassmannianKernel.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@


class GrassmannianKernel(Kernel, ABC):
"""This is a blueprint for Euclidean kernels implemented in the :py:mod:`kernels` module ."""
"""The parent class for Grassmannian kernels implemented in the :py:mod:`kernels` module ."""

def __init__(self):
super().__init__()
Expand All @@ -17,9 +17,9 @@ def calculate_kernel_matrix(self, points: list[GrassmannPoint], p: int = None):
"""
Compute the kernel matrix given a list of points on the Grassmann manifold.
:param points: Points projected on the Grassmann manifold
:param points: Points on the Grassmann manifold
:param p: Number of independent p-planes of each Grassmann point.
:return: :class:`ndarray`
:return: :class:`ndarray` The kernel matrix.
"""
nargs = len(points)
# Define the pairs of points to compute the entries of the kernel matrix.
Expand Down

0 comments on commit 164f072

Please sign in to comment.