Skip to content

Commit

Permalink
added __eq__ routines to basis, parameter, quadrature and poly
Browse files Browse the repository at this point in the history
  • Loading branch information
psesh committed Nov 21, 2021
1 parent c2646fb commit 948712c
Show file tree
Hide file tree
Showing 6 changed files with 109 additions and 24 deletions.
7 changes: 7 additions & 0 deletions equadratures/basis.py
Expand Up @@ -99,6 +99,13 @@ def set_orders(self, orders):
self.elements = basis
self.cardinality = len(basis)

def __eq__(self, another_basis):
"""Checks whether two basis are the same."""
if self.basis_type.lower() == another_basis.basis_type.lower() and \
np.array_equiv(self.elements, another_basis.elements):
return True
else:
return False
def get_cardinality(self):
""" Returns the number of elements of an index set.
Expand Down
2 changes: 1 addition & 1 deletion equadratures/distributions/gaussian.py
Expand Up @@ -26,7 +26,7 @@ def __init__(self, mean, variance):
self.variance = 1.0
else:
self.variance = variance

super
if self.variance <= 0:
raise ValueError('Invalid Gaussian distribution parameters. Variance should be positive.')

Expand Down
21 changes: 20 additions & 1 deletion equadratures/distributions/template.py
Expand Up @@ -15,14 +15,33 @@ class Distribution(object):
:param double upper:
Upper bound of the support of the distribution.
"""
def __init__(self, mean=None, variance=None, lower=None, upper=None, shape=None, scale=None, rate=None):
def __init__(self, name=None, mean=None, variance=None, lower=None, upper=None, shape=None, scale=None, rate=None):
self.name = name
self.mean = mean
self.variance = variance
self.lower = lower
self.upper = upper
self.rate = rate
self.scale = scale
self.x_range_for_pdf = []

def __eq__(self, second_distribution):
"""
Returns a boolean to clarify if two distributions are the same.
:param
"""
if self.name == second_distribution.name and \
self.mean == second_distribution.mean and \
self.variance == second_distribution.variance and \
self.lower == second_distribution.lower and \
self.upper == second_distribution.upper and \
self.rate == self.rate and \
self.scale == self.scale and \
self.x_range_for_pdf == self.x_range_for_pdf:
return True
else:
False
def get_description(self):
"""
Returns the description of the distribution.
Expand Down
17 changes: 12 additions & 5 deletions equadratures/parameter.py
Expand Up @@ -23,7 +23,7 @@
import scipy as sc

class Parameter(object):
""" This class defines a univariate parameter.
""" This class defines a univariate parameter.
Parameters
----------
Expand Down Expand Up @@ -52,21 +52,21 @@ class Parameter(object):
endpoints : str, optional
If set to ``both``, then the quadrature points and weights will have end-points, based on Gauss-Lobatto quadrature rules. If set to ``upper`` or ``lower`` a Gauss-Radau rule is used to compute one end-point at either the upper or lower bound.
weight_function: Weight, optional
An instance of Weight, which contains a bespoke analytical or data-driven weight (probability density) function.
An instance of Weight, which contains a bespoke analytical or data-driven weight (probability density) function.
Examples
--------
A uniform parameter
>>> param = eq.Parameter(distribution='uniform', lower=-2, upper=2., order=3)
A beta parameter
>>> param = eq.Parameter(distribution='beta', lower=-2., upper=15., order=4,
>>> param = eq.Parameter(distribution='beta', lower=-2., upper=15., order=4,
>>> shape_parameter_A=3.2, shape_parameter_B=1.7)
A data-driven parameter
>>> pdf = eq.Weight( stats.gaussian_kde(data, bw_method='silverman'),
>>> pdf = eq.Weight( stats.gaussian_kde(data, bw_method='silverman'),
>>> support=[-3, 3.2])
>>> param = eq.Parameter(distribution='analytical',
>>> param = eq.Parameter(distribution='analytical',
>>> weight_function=pdf, order=2)
References
Expand Down Expand Up @@ -139,6 +139,13 @@ def _set_distribution(self):
self.mean = self.distribution.mean
self.variance = self.distribution.variance

def __eq__(self, param):
"""Checks whether two parameters are the same."""
if self.distribution == param.distribution and \
self.order == param.order:
return True
else:
return False
def plot_orthogonal_polynomials(self, ax=None, order_limit=None, number_of_points=200, show=True):
""" Plots the first few orthogonal polynomials. See :meth:`~equadratures.plot.plot_orthogonal_polynomials` for full description. """
return plot.plot_orthogonal_polynomials(self,ax,order_limit,number_of_points,show)
Expand Down
76 changes: 59 additions & 17 deletions equadratures/poly.py
Expand Up @@ -30,7 +30,7 @@ class Poly(object):
- **mesh** (str): Avaliable options are: ``monte-carlo``, ``sparse-grid``, ``tensor-grid``, ``induced``, or ``user-defined``. Note that when the ``sparse-grid`` option is invoked, the sparse pseudospectral approximation method [1] is the adopted. One can think of this as being the correct way to use sparse grids in the context of polynomial chaos [2] techniques.
- **subsampling-algorithm** (str): The ``subsampling-algorithm`` input refers to the optimisation technique for subsampling. In the aforementioned four sampling strategies, we generate a logarithm factor of samples above the required amount and prune down the samples using an optimisation technique (see [1]). Existing optimisation strategies include: ``qr``, ``lu``, ``svd``, ``newton``. These refer to QR with column pivoting [2], LU with row pivoting [3], singular value decomposition with subset selection [2] and a convex relaxation via Newton's method for determinant maximization [4]. Note that if the ``tensor-grid`` option is selected, then subsampling will depend on whether the Basis argument is a total order index set, hyperbolic basis or a tensor order index set.
- **sampling-ratio** (float): Denotes the extent of undersampling or oversampling required. For values equal to unity (default), the number of rows and columns of the associated Vandermonde-type matrix are equal.
- **sample-points** (numpy.ndarray): A numpy ndarray with shape (number_of_observations, dimensions) that corresponds to a set of sample points over the parameter space.
- **sample-points** (numpy.ndarray): A numpy ndarray with shape (number_of_observations, dimensions) that corresponds to a set of sample points over the parameter space. Can use ``sample-inputs`` too.
- **sample-outputs** (numpy.ndarray): A numpy ndarray with shape (number_of_observations, 1) that corresponds to model evaluations at the sample points. Note that if ``sample-points`` is provided as an input, then the code expects ``sample-outputs`` too.
- **sample-gradients** (numpy.ndarray): A numpy ndarray with shape (number_of_observations, dimensions) that corresponds to a set of sample gradient values over the parameter space.
solver_args : dict, optional
Expand Down Expand Up @@ -125,6 +125,10 @@ def __init__(self, parameters, basis, method=None, sampling_args=None, solver_ar
self.inputs = sampling_args.get('sample-points')
sampling_args_flag = 1
self.mesh = 'user-defined'
if 'sample-inputs' in sampling_args:
self.inputs = sampling_args.get('sample-inputs')
sampling_args_flag = 1
self.mesh = 'user-defined'
if 'sample-outputs' in sampling_args:
self.outputs = sampling_args.get('sample-outputs')
sampling_args_flag = 1
Expand Down Expand Up @@ -158,7 +162,31 @@ def __init__(self, parameters, basis, method=None, sampling_args=None, solver_ar
else:
print('WARNING: Method not declared.')

def __add__(self, *args):
def __eq__(self, another_poly):
""" Verifies if two polynomial instances are the same. Two polynomials are defined to be the same if (i) they have the same
basis terms, and (ii) the list of parameters are identical.
Parameters
----------
another_poly : Poly
Another ``Poly`` instance against which the ``self`` object will be compared.
Returns
--------
bool
True or False depending on whether the arguments are deemed to be equivalent.
"""
if self.basis == another_poly.basis and \
self.parameters == self.parameters:
return True
else:
return False

def __add__(self, another_poly):
""" Adds polynomials.
Returns
Expand All @@ -168,14 +196,21 @@ def __add__(self, *args):
An instance of the Poly class.
"""
polynew = deepcopy(self)
for other in args:
polynew.coefficients += other.coefficients
if np.all( polynew._quadrature_points - other._quadrature_points ) == 0:
polynew._model_evaluations += other._model_evaluations
return polynew

def __sub__(self, *args):
new_poly = deepcopy(self)
if self == another_poly:
if self.quadrature == another_poly.quadrature:
new_poly.coefficients += another_poly.coefficients
new_poly._model_evaluations += another_poly._model_evaluations
else:
y1 = new_poly._model_evaluations.flatten()
y2 = another_poly.get_polyfit(self._quadrature_points).flatten()
new_poly._model_evaluations = (y1 + y2)
new_poly._set_coefficients()
return new_poly
else:
raise ValueError('cannot add the two polynomials!')

def __sub__(self, another_poly):
""" Subtracts polynomials.
Returns
Expand All @@ -185,12 +220,19 @@ def __sub__(self, *args):
An instance of the Poly class.
"""
polynew = deepcopy(self)
for other in args:
polynew.coefficients -= other.coefficients
if np.all( polynew._quadrature_points - other._quadrature_points ) == 0:
polynew._model_evaluations -= other._model_evaluations
return polynew
new_poly = deepcopy(self)
if self == another_poly:
if self.quadrature == another_poly.quadrature:
new_poly.coefficients -= another_poly.coefficients
new_poly._model_evaluations -= another_poly._model_evaluations
else:
y1 = new_poly._model_evaluations.flatten()
y2 = another_poly.get_polyfit(self._quadrature_points).flatten()
new_poly._model_evaluations = (y1 - y2)
new_poly._set_coefficients()
return new_poly
else:
raise ValueError('cannot subtract the two polynomials!')

def plot_polyfit_1D(self, ax=None, uncertainty=True, output_variances=None, number_of_points=200, show=True):
""" Plots a 1D only polynomial fit to the data. See :meth:`~equadratures.plot.plot_polyfit_1D` for full description. """
Expand Down Expand Up @@ -651,7 +693,7 @@ def get_points_and_weights(self):
return self._quadrature_points, self._quadrature_weights

def get_polyfit(self, stack_of_points, uq=False):
""" Evaluates the /polynomial approximation of a function (or model data) at prescribed points.
""" Evaluates the polynomial approximation of a function (or model data) at prescribed points.
Parameters
----------
Expand Down
10 changes: 10 additions & 0 deletions equadratures/quadrature.py
Expand Up @@ -6,6 +6,7 @@
from equadratures.sampling_methods.induced import Induced
from equadratures.sampling_methods.sampling_template import Sampling
import numpy as np
from numpy.core.numeric import array_equiv
class Quadrature(object):
""" The class defines a Sampling object. It serves as a template for all sampling methodologies.
Expand Down Expand Up @@ -46,6 +47,15 @@ def __init__(self, parameters, basis, points, mesh, corr=None, oversampling=7.0)
else:
error_message()

def __eq__(self, another_quadrature):
"""Checks whether two quadrature instances are the same.
"""
if np.array_equiv(self.points, another_quadrature.samples.points) and \
np.array_equiv(self.samples.weights):
return True
else:
return False

def get_points(self):
""" Returns the quadrature points.
Expand Down

0 comments on commit 948712c

Please sign in to comment.