"""A module containing mathematical functions"""
from typing import Union
import numpy as np
from numpy.fft import fft, ifft
# It may still be interesting for futre performance tuning
# to try to replace numpy.fft with pyfftw.
# The easiest way would be to use:
# from pyfftw.interfaces.numpy_fft import fft
# from pyfftw.interfaces.numpy_fft import ifft
# However, probably the multiprocessing module is going
# to be the best solution to improve the performance.
UNIT_VECTOR = np.array([[1., 0., 0.],
[0., 1., 0.],
[0., 0., 1.]])
[docs]def correlation(input1, input2=None, normalise=False) -> np.ndarray:
"""
The correlation of two vectors
The Fast Correlation Algorithm (FCA) is utilised. If only a single input is
provided, the autocorrelation is calculated.
Parameters
----------
input1 : numpy.ndarray
A 1D ``array`` of data.
input2 : numpy.ndarray, optional
A 1D ``array`` of data. If `None`, autocorrelation of ``input1`` is
calculated. Default is `None`.
normalise : bool, optional
If `True`, the correlation is normalised at each point to the number of
contributions to that point. Default is `False`.
Returns
-------
numpy.ndarray
A 1D ``array`` of the same length as the ``input1`` containing the
correlation between ``input1`` and ``input2`` (or autocorrelation of
``input1`` if ``input2`` is `None`)
"""
num_steps = len(input1)
fft1 = fft(input1, n=(num_steps * 2), axis=0)
if input2 is None:
fft2 = fft1
else:
fft2 = fft(input2, n=(num_steps * 2), axis=0)
# Calculate the cyclic correlation function
cyclic_corr = ifft(np.conjugate(fft1) * fft2, axis=0)
# Normalise for variable number of contributions to each correlation:
# 1 / (N - m)
# where m is the number of each individual step
if normalise:
prefactor = 1. / (num_steps - np.arange(num_steps))
if len(np.shape(cyclic_corr)) > 1:
cyclic_corr = np.sum(cyclic_corr, axis=1)
else:
prefactor = 1.
corr = prefactor * np.real(cyclic_corr[0:num_steps])
return corr
# We could trying numba.jit here later to speed things up.
[docs]def faster_correlation(input1, input2) -> np.ndarray:
"""
The correlation of two vectors.
The Fast Correlation Algorithm (FCA) is utilised.
Parameters
----------
input1 : numpy.ndarray
A 1D ``array`` of data.
input2 : numpy.ndarray, optional
A 1D ``array`` of data. If `None`, autocorrelation of ``input1`` is
calculated. Default is `None`.
Returns
-------
numpy.ndarray
A 1D ``array`` of the same length as the ``input1`` containing the
correlation between ``input1`` and ``input2`` (or autocorrelation of
``input1`` if ``input2`` is `None`)
"""
num_steps = len(input1)
fft1 = fft(input1, n=(num_steps * 2), axis=0)
fft2 = fft(input2, n=(num_steps * 2), axis=0)
# Calculate the cyclic correlation function
cyclic_corr = ifft(np.conjugate(fft1) * fft2, axis=0)
# Normalise for variable number of contributions to each correlation:
# 1 / (N - m)
# where m is the number of each individual step
prefactor = 1. / (num_steps - np.arange(num_steps))
# I have to guarantee that the array is a 2D array on input
cyclic_corr = np.sum(cyclic_corr, axis=1)
corr = prefactor * np.real(cyclic_corr[0:num_steps])
return corr
# We could trying numba.jit here later to speed things up.
[docs]def faster_autocorrelation(input1: np.ndarray,
weights: Union[np.ndarray,float] = None) -> np.ndarray:
"""
The autocorrelation of a vector.
The Fast Correlation Algorithm (FCA) is utilised.
Parameters
----------
input1 : numpy.ndarray
A 1D ``array`` of data.
Returns
-------
numpy.ndarray
A 1D ``array`` of the same length as the ``input1`` containing the
correlation between ``input1`` and ``input2`` (or autocorrelation of
``input1`` if ``input2`` is `None`)
"""
num_steps = len(input1)
fft1 = fft(input1, n=(num_steps * 2), axis=0)
# Calculate the cyclic correlation function
cyclic_corr = ifft(np.conjugate(fft1) * fft1, axis=0)
# Normalise for variable number of contributions to each correlation:
# 1 / (num_steps - m)
# where m is the number of each individual step
prefactor = 1. / (num_steps - np.arange(num_steps))
# I have to guarantee that the array is a 2D array on input
if weights is not None:
try:
temp_weights = weights.reshape((1, len(weights)))
except AttributeError:
temp_weights = weights
cyclic_corr *= temp_weights
cyclic_corr = np.sum(cyclic_corr, axis=1)
corr = prefactor * np.real(cyclic_corr[0:num_steps])
return corr
def _convolution(input1, input2):
"""
The convolution of two inputs
THIS FUNCTION HAS NOT BEEN IMPLEMENTED AND SO IS CURRENTLY PRIVATE
Parameters
----------
input1 : numpy.ndarray
A 1D ``array`` of data.
input2 : numpy.ndarray
A 1D ``array`` of data.
Raises
-------
NotImplementedError
THIS FUNCTION HAS NOT BEEN IMPLEMENTED
"""
raise NotImplementedError