Fit curves with high precision using Multi-resolution analysis and Wavelet transform. The module directly implements Orthogonal Gausslets as described in the paper, however, in addition, the module also has hat basis functions and allows for the construction of custom Gausslets.
To install the latest version
pip install mrafit
To install a specific version (example 1.1.2)
pip install mrafit==1.1.2
mrafit allows reconstruction of a curve by expressing it in terms of localized basis functions. In other words, a curve represented by a list of points
Quantum chemistry involves calculating electronic states in Atoms and molecules with a large number of electrons using Schrödinger's equation, which makes it particularly challenging due to the complexity involved in electron-electron interactions. Orthogonal wavelet transformation can drastically simplify quantum chemistry calculations by reducing complexity from O(4) to O(2) while calculating the electron interaction Potential
Since any 2-d, 3-d curve can be reduced to a 1-d representation of coefficients, this can provide a massive computational advantage in ML problems where parametric learning of curves is required. Instead of learning points, one can simply apply mrafit and learn mra coefficients instead.
- To fit any function (type Callable) using a basis WaveletBasis (class Wavelet)
from mrafit.wavelet_basis.WaveletBasis
basis = WaveletBasis()
coeff, Y, error = basis.get_mra_approx(func, X)
In the above example, WaveletBasis by default is Haar basis, it can be replaced with one of the available basis in the module. In case of Gausslet basis, the code is modified as
from mrafit.wavelet_basis.GaussletBasis
basis = GaussletBasis(resolution = 0.1)
coeff, Y, error = basis.get_mra_approx(func, X)
here,
function : a callable function of function values (function or numpy array)
X : Uniform 1-d grid (numpy array)
coeffs: values of coefficients of given basis function (numpy array)
approx_function: values of approximated function using given basis (numpy array)
error: error of the approximate values with respect to the original value of the function
- To reconstruct any function of the coefficients of a basis is provided
Y = basis.get_reconstructed_func(coeffs, X)
- Example use case with GaussletBasis
import mrafit.wavelet_bases as wavelet_bases
import numpy as np
# From wavelet_bases, an instance of any available basis can be created. For example, to use the orthogonal Gausslet basis, we can define
gb = wavelet_bases.GaussletBasis()
func = lambda x : np.exp(-x**2/3) * (x**2 - x + 1)
# To approximate any given function defined over domain \(-1, 1\) with respect to a basis
X = np.linspace(-1, 1, 100)
coeffs, approx_func, error = gb.get_mra_approx(func, X)
# The example below includes a list of all steps to fit a synthetic function using mrafit
""" This parameter controls how precisely you want to approximate a function; the smaller the value better the approximation."22"
resolution = 0.5
wid = 10
N = 800
error_bound = 10e-2 * resolution
""" Use this section if you want to test gausslet with Stephen White's coefficients"""
gb = wavelet_bases.GaussletBasis(resolution=resolution)
""" Sample function to be approximated, you can change it as per your need"""
func = lambda x : np.exp(-x**2/3) * (x**2 - x + 1)
""" Finally applying the mra approximation"""
X = np.linspace(-wid, wid, N)
coeffs, approx_func, error = gb.get_mra_approx(func, X)
plt.plot(X, approx_func)
plt.plot(X, np.vectorize(func)(X))
The image below shows the approximate function vs the actual function

Apart from the error obtained from get_mra_approx function, one can determine the performance of a basis function using get_orthongonality and get_completeness functions. This is especially useful for the bases which are known to be orthogonal or complete, but due to numerical transformation can give unexpected results.
from mrafit.wavelet_basis.WaveletBasis
basis = WaveletBasis()
coeff, Y, error = basis.get_mra_approx(func, X)
orthogonality = basis.get_orthogonality()
completness = basis.get_completeness()
Both returns score between 0(least complete) to 1 (most complete)
In the get_mra_approx function, we input a parameter called X : a uniform one-dimensional grid expressed as a numpy array. The accuracy of how well a curve can be fit using a basis is highly sensitive to X. If X is a fine grid, it results in high accuracy but also incurs a high computational cost. On the other hand, even a coarse grid can provide fairly accurate results in many cases. But X alone doesn't determine accuracy; when initializing a basis, there is an optional parameter resolution of type float. It determines the support of a single basis function : if a resolution = 1, it means a single basis function has a support of width 1, and if resolution = 0.5, the same basis function is shrunk to half making its support of width 0.5. This means resolution size can be reduced to achieve further gain in accuracy. By default resolution = 1 for most bases. There is an upper bound on accuracy that a basis can achieve with a given resolution, i.e. increasing grid resolution leads to asymptotic increase in accuracy.
But the more critical part is choosing the right X for a given resolution. If resolution is too small and grid size is relatively large, the get_approx_func will result in a highly erroneous fit. A good rule is to assign values to grid spacing and resolution proportionately, for example we can have resolution as a single independent variable and rest of the parameters dependent on it as
resolution = 0.1
N = int(100/resolution)
X = np.linspace(-5, 5, N)
To see this in practice, refer to effect_of_resolution.ipynb notebook in examples





