from abc import abstractmethod
import numpy as np
from .base import Base, Property
from .types.array import StateVectors
from .types.state import State
[docs]
class Kernel(Base):
"""Kernel base type
A Kernel provides a means to translate state space or measurement space into kernel space.
"""
@abstractmethod
def __call__(self, state1, state2=None):
r"""
Compute the kernel state of a pair of :class:`~.State` objects
Parameters
----------
state1 : :class:`~.State`
state2 : :class:`~.State`
Returns
-------
StateVectors
kernel state of a pair of input :class:`~.State` objects
"""
raise NotImplementedError
@staticmethod
def _get_state_vectors(state1, state2):
if isinstance(state1, State):
state_vector1 = state1.state_vector
else:
state_vector1 = state1
if state2 is None:
state_vector2 = state_vector1
else:
if isinstance(state2, State):
state_vector2 = state2.state_vector
else:
state_vector2 = state2
return state_vector1, state_vector2
[docs]
class QuadraticKernel(Kernel):
r"""Quadratic Kernel type
This kernel returns the quadratic kernel state vector from a pair of
:class:`~.KernelParticleState` state vectors.
The Quadratic kernel of state vectors :math:`\mathbf{x}` and
:math:`\mathbf{x}'` is defined as:
.. math::
\mathtt{k}\left(\mathbf{x}, \mathbf{x}'\right) =
\left(\alpha \langle \mathbf{x}, \mathbf{x}' \rangle + c\right)^2
"""
c: float = Property(
default=1,
doc="Free parameter trading off the influence of higher-order versus lower-order "
"terms in the polynomial. Default is 1.")
ialpha: float = Property(default=1e1, doc="Slope. Range is [1e0, 1e4].")
def __call__(self, state1, state2=None):
r"""Calculate the Quadratic Kernel transformation for a pair of state vectors
Parameters
----------
state1 : :class:`~.KernelParticleState`
state2 : :class:`~.KernelParticleState`
Returns
-------
StateVectors
Transformed state vector in kernel space.
"""
state_vector1, state_vector2 = self._get_state_vectors(state1, state2)
return (state_vector1.T@state_vector2/self.ialpha + self.c) ** 2
[docs]
class QuarticKernel(Kernel):
r"""Quartic Kernel
This kernel returns the quartic kernel state from a pair of
:class:`~.KernelParticleState` objects.
The Quartic kernel of state vectors :math:`\mathbf{x}` and
:math:`\mathbf{x}'` is defined as:
.. math::
\mathtt{k}(\mathbf{x}, \mathbf{x}') =
\left(\alpha \langle \mathbf{x}, \mathbf{x}' \rangle + c\right)^4
"""
c: float = Property(
default=1,
doc="Free parameter trading off the influence of higher-order versus lower-order "
"terms in the polynomial. Default is 1.")
ialpha: float = Property(default=1e1, doc="Slope. Range is [1e0, 1e4].")
def __call__(self, state1, state2=None):
r"""Calculate the Quartic Kernel transformation for a pair of state vectors
Parameters
----------
state1 : :class:`~.KernelParticleState`
state2 : :class:`~.KernelParticleState`
Returns
-------
StateVectors
Transformed state in kernel space.
"""
state_vector1, state_vector2 = self._get_state_vectors(state1, state2)
return (state_vector1.T@state_vector2/self.ialpha + self.c) ** 4
[docs]
class GaussianKernel(Kernel):
r"""Gaussian Kernel
This kernel returns the Gaussian kernel state vector from a pair of
:class:`~.KernelParticleState` state vectors.
The Gaussian kernel of state vectors :math:`\mathbf{x}` and
:math:`\mathbf{x}'` is defined as:
.. math::
\mathtt{k}(\mathbf{x}, \mathbf{x}') =
\mathrm{exp}\left(-\frac{||\mathbf{x} - \mathbf{x}'||^{2}}{2\pi\sigma^2}\right)
"""
variance: float = Property(
default=1e1,
doc=r"Denoted as :math:`\sigma^2` in the equation above. Determines the width of the "
r"Gaussian kernel. Range is [1e0, 1e2].")
def __call__(self, state1, state2=None):
r"""Calculate the Gaussian Kernel transformation for a pair of state vectors
Parameters
----------
state1 : :class:`~.KernelParticleState`
state2 : :class:`~.KernelParticleState`
Returns
-------
StateVectors
Transformed state vector in kernel space.
"""
state_vector1, state_vector2 = self._get_state_vectors(state1, state2)
diff_tilde_x = (state_vector1.T[:, :, None] - state_vector2.T[:, None, :]) ** 2
diff_tilde_x_sum = np.sum(diff_tilde_x, axis=0)
k_tilde_x = np.exp(-diff_tilde_x_sum/(2*self.variance)) / np.sqrt(2*np.pi*self.variance)
return StateVectors(k_tilde_x)