Orthonormal Polynomials in PyTorch
Source code in plot.py
AbstractOrthoPolys
Bases: object
Abstract class for classic orthogonal polynomials.
Source code in torchorthopolys/orthopolys.py
__call__
Evaluate polynomials.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
n
|
int
|
non-negative maximum degree of the polynomial. |
required |
x
|
Tensor
|
nodes at which to evaluate. |
required |
Returns:
| Name | Type | Description |
|---|---|---|
y |
Tensor
|
polynomial evaluations with shape |
Source code in torchorthopolys/orthopolys.py
coeffs
Evaluate coefficients.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
n
|
int
|
non-negative maximum degree of the polynomial. |
required |
Returns:
| Name | Type | Description |
|---|---|---|
c |
Tensor
|
coefficients with shape |
Source code in torchorthopolys/orthopolys.py
deriv
Evaluate first derivative of polynomials.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
n
|
int
|
non-negative maximum degree of the polynomial. |
required |
x
|
Tensor
|
nodes at which to evaluate. |
required |
Returns:
| Name | Type | Description |
|---|---|---|
y |
Tensor
|
polynomial evaluations with shape |
Source code in torchorthopolys/orthopolys.py
lweight
Log of the weight function.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
x
|
Tensor
|
nodes at which to evaluate. |
required |
Returns:
| Name | Type | Description |
|---|---|---|
y |
Tensor
|
log-scaled weight evaluations with the same shape as |
Source code in torchorthopolys/orthopolys.py
weight
The weight function.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
x
|
Tensor
|
nodes at which to evaluate. |
required |
Returns:
| Name | Type | Description |
|---|---|---|
y |
Tensor
|
weight evaluations with the same shape as |
integral
Integral of the polynomials times the weight function from self.a to x
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
n
|
int
|
non-negative maximum degree of the polynomial. |
required |
Returns:
| Name | Type | Description |
|---|---|---|
y |
Tensor
|
integral values |
Source code in torchorthopolys/orthopolys.py
Hermite
Bases: AbstractOrthoPolys
Orthonormal Hermite polynomials supported on \((-\infty,\infty)\) with the weight normalized to be a density function.
Examples:
>>> u = scipy.stats.qmc.Sobol(d=1,rng=7).random(2**16)[:,0]
>>> x = torch.from_numpy(scipy.stats.norm.ppf(u,loc=loc,scale=scale))
>>> n = 4
>>> y = poly(n,x)
>>> y.shape
torch.Size([5, 65536])
>>> (y[:,None]*y[None,:]).mean(-1)
tensor([[ 1.0000e+00, 5.7021e-07, -2.4570e-05, 1.2231e-05, -2.2798e-04],
[ 5.7021e-07, 9.9997e-01, 2.1992e-05, -4.9851e-04, 1.5973e-04],
[-2.4570e-05, 2.1992e-05, 9.9937e-01, 2.4418e-04, -4.3017e-03],
[ 1.2231e-05, -4.9851e-04, 2.4418e-04, 9.9481e-01, 1.4077e-03],
[-2.2798e-04, 1.5973e-04, -4.3017e-03, 1.4077e-03, 9.7405e-01]])
>>> lrho = poly.lweight(x)
>>> lrhohat = torch.from_numpy(scipy.stats.norm.logpdf(x.numpy(),loc=loc,scale=scale))
>>> assert torch.allclose(lrho,lrhohat)
>>> Cs = torch.exp(poly._lnorm(n))
>>> xt = poly.scale*x+poly.shift
>>> assert torch.allclose(y[0],torch.sqrt(Cs[0]/Cs[0])/poly.c00*(1+0*xt))
>>> assert torch.allclose(y[1],torch.sqrt(Cs[0]/Cs[1])/poly.c00*(2*xt))
>>> assert torch.allclose(y[2],torch.sqrt(Cs[0]/Cs[2])/poly.c00*(4*xt**2-2))
>>> assert torch.allclose(y[3],torch.sqrt(Cs[0]/Cs[3])/poly.c00*(8*xt**3-12*xt))
>>> assert torch.allclose(y[4],torch.sqrt(Cs[0]/Cs[4])/poly.c00*(16*xt**4-48*xt**2+12))
>>> coeffs = poly.coeffs(n)
>>> coeffs.shape
torch.Size([5, 5])
>>> coeffs
tensor([[ 1.0000, 0.0000, 0.0000, 0.0000, 0.0000],
[ 1.1557, 0.3679, 0.0000, 0.0000, 0.0000],
[ 0.2374, 0.6013, 0.0957, 0.0000, 0.0000],
[-0.7853, 0.1513, 0.1916, 0.0203, 0.0000],
[-0.6593, -0.5778, 0.0556, 0.0470, 0.0037]])
>>> xpows = x[...,None]**torch.arange(n+1)
>>> xpows.shape
torch.Size([65536, 5])
>>> yhat = torch.einsum("ij,...j->i...",coeffs,xpows) # generally unstable
>>> yhat.shape
torch.Size([5, 65536])
>>> assert torch.allclose(y,yhat)
>>> yp = poly.deriv(n,x)
>>> yp.shape
torch.Size([5, 65536])
>>> xpowsm1 = x[...,None]**torch.arange(-1,n)
>>> xpowsm1.shape
torch.Size([65536, 5])
>>> yphat = torch.einsum("ij,...j->i...",coeffs*torch.arange(n+1),xpowsm1) # generally unstable
>>> yphat.shape
torch.Size([5, 65536])
>>> assert torch.allclose(yphat,yp)
>>> x = torch.linspace(loc-2*scale,loc+2*scale,6)
>>> n = 8
>>> v = poly.integral(n,x)
>>> v.shape
torch.Size([9, 6])
>>> vhat = torch.ones_like(v)
>>> for i in range(len(x)):
... ttrap = torch.linspace(loc-5*scale,x[i],100001)
... ytrap = poly(n=n,x=ttrap)*poly.weight(ttrap)
... vhat[:,i] = torch.trapezoid(ytrap,ttrap)
>>> assert torch.allclose(vhat,v,atol=1e-3)
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
loc
|
float
|
weight distribution will be |
0
|
scale
|
float
|
weight distribution will be |
1 / sqrt(2)
|
Source code in torchorthopolys/orthopolys.py
Laguerre
Bases: AbstractOrthoPolys
Orthonormal Generalized Laguerre polynomials supported on \([0,\infty)\) with the weight normalized to be a density function.
Examples:
>>> loc = -np.pi
>>> scale = np.exp(1)
>>> alpha = -1/np.sqrt(3)
>>> poly = Laguerre(alpha=alpha,loc=loc,scale=scale)
>>> u = scipy.stats.qmc.Sobol(d=1,rng=7).random(2**16)[:,0]
>>> x = torch.from_numpy(scipy.stats.gamma.ppf(u,a=alpha+1,loc=loc,scale=scale))
>>> n = 4
>>> y = poly(n,x)
>>> y.shape
torch.Size([5, 65536])
>>> (y[:,None]*y[None,:]).mean(-1)
tensor([[ 1.0000e+00, 1.1409e-05, -1.1488e-04, 4.2222e-04, -6.7890e-04],
[ 1.1409e-05, 9.9967e-01, 2.4873e-03, -8.2370e-03, 1.2887e-02],
[-1.1488e-04, 2.4873e-03, 9.8360e-01, 5.1614e-02, -8.0659e-02],
[ 4.2222e-04, -8.2370e-03, 5.1614e-02, 8.3976e-01, 2.5730e-01],
[-6.7890e-04, 1.2887e-02, -8.0659e-02, 2.5730e-01, 5.5508e-01]])
>>> lrho = poly.lweight(x)
>>> lrhohat = torch.from_numpy(scipy.stats.gamma.logpdf(x.numpy(),a=alpha+1,loc=loc,scale=scale))
>>> assert torch.allclose(lrho,lrhohat,atol=1e-3)
>>> Cs = torch.exp(poly._lnorm(n))
>>> xt = poly.scale*x+poly.shift
>>> assert torch.allclose(y[0],torch.sqrt(Cs[0]/Cs[0])/poly.c00*(1+0*xt))
>>> assert torch.allclose(y[1],torch.sqrt(Cs[0]/Cs[1])/poly.c00*(-xt+alpha+1))
>>> assert torch.allclose(y[2],torch.sqrt(Cs[0]/Cs[2])/poly.c00*(1/2*(xt**2-2*(alpha+2)*xt+(alpha+1)*(alpha+2))))
>>> assert torch.allclose(y[3],torch.sqrt(Cs[0]/Cs[3])/poly.c00*(1/6*(-xt**3+3*(alpha+3)*xt**2-3*(alpha+2)*(alpha+3)*xt+(alpha+1)*(alpha+2)*(alpha+3))))
>>> assert torch.allclose(y[4],torch.sqrt(Cs[0]/Cs[4])/poly.c00*(1/24*(xt**4-4*(alpha+4)*xt**3+6*(alpha+3)*(alpha+4)*xt**2-4*(alpha+2)*(alpha+3)*(alpha+4)*xt+(alpha+1)*(alpha+2)*(alpha+3)*(alpha+4))))
>>> coeffs = poly.coeffs(n)
>>> coeffs.shape
torch.Size([5, 5])
>>> coeffs
tensor([[ 1.0000, 0.0000, 0.0000, 0.0000, 0.0000],
[-1.1276, -0.5659, 0.0000, 0.0000, 0.0000],
[-1.2323, -0.1791, 0.1234, 0.0000, 0.0000],
[-0.7878, 0.3052, 0.1740, -0.0168, 0.0000],
[-0.2235, 0.6433, 0.1274, -0.0413, 0.0017]])
>>> xpows = x[...,None]**torch.arange(n+1)
>>> xpows.shape
torch.Size([65536, 5])
>>> yhat = torch.einsum("ij,...j->i...",coeffs,xpows) # generally unstable
>>> yhat.shape
torch.Size([5, 65536])
>>> assert torch.allclose(y,yhat)
>>> yp = poly.deriv(n,x)
>>> yp.shape
torch.Size([5, 65536])
>>> xpowsm1 = x[...,None]**torch.arange(-1,n)
>>> xpowsm1.shape
torch.Size([65536, 5])
>>> yphat = torch.einsum("ij,...j->i...",coeffs*torch.arange(n+1),xpowsm1) # generally unstable
>>> yphat.shape
torch.Size([5, 65536])
>>> assert torch.allclose(yphat,yp)
>>> x = torch.linspace(poly.a,10,7)[1:]
>>> n = 8
>>> v = poly.integral(n,x)
>>> v.shape
torch.Size([9, 6])
>>> vhat = torch.ones_like(v)
>>> for i in range(len(x)):
... ttrap = torch.linspace(poly.a,x[i],100001)[1:]
... ytrap = poly(n=n,x=ttrap)*poly.weight(ttrap)
... vhat[:,i] = torch.trapezoid(ytrap,ttrap)
>>> assert torch.allclose(vhat,v,atol=2.5e-2)
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
alpha
|
float
|
parameter \(\alpha>-1\). |
0
|
loc
|
float
|
weight distribution will be |
0
|
scale
|
float
|
weight distribution will be |
1
|
Source code in torchorthopolys/orthopolys.py
Jacobi
Bases: AbstractOrthoPolys
Orthonormal Jacobi polynomials supported on \([-1,1]\) with the weight normalized to be a density function.
Examples:
>>> loc = -np.pi
>>> scale = np.exp(1)
>>> alpha = 1/2
>>> beta = 3/4
>>> poly = Jacobi(alpha=alpha,beta=beta,loc=loc,scale=scale)
>>> u = scipy.stats.qmc.Sobol(d=1,rng=7).random(2**16)[:,0]
>>> x = torch.from_numpy(scipy.stats.beta.ppf(u,a=beta+1,b=alpha+1,loc=loc,scale=scale))
>>> n = 4
>>> y = poly(n,x)
>>> y.shape
torch.Size([5, 65536])
>>> (y[:,None]*y[None,:]).mean(-1)
tensor([[ 1.0000e+00, 1.4714e-08, -1.1409e-07, 1.9097e-07, -6.1552e-07],
[ 1.4714e-08, 1.0000e+00, 2.2747e-07, -7.7976e-07, 1.0676e-06],
[-1.1409e-07, 2.2747e-07, 1.0000e+00, 1.1397e-06, -2.8870e-06],
[ 1.9097e-07, -7.7976e-07, 1.1397e-06, 1.0000e+00, 3.6799e-06],
[-6.1552e-07, 1.0676e-06, -2.8870e-06, 3.6799e-06, 9.9999e-01]])
>>> lrho = poly.lweight(x)
>>> lrhohat = torch.from_numpy(scipy.stats.beta.logpdf(x.numpy(),a=beta+1,b=alpha+1,loc=loc,scale=scale))
>>> assert torch.allclose(lrho,lrhohat,1e-3)
>>> Cs = torch.exp(poly._lnorm(n))
>>> xt = poly.scale*x+poly.shift
>>> assert torch.allclose(y[0],torch.sqrt(Cs[0]/Cs[0])/poly.c00*(1+0*xt))
>>> assert torch.allclose(y[1],torch.sqrt(Cs[0]/Cs[1])/poly.c00*((alpha+1)+(alpha+beta+2)*(xt-1)/2))
>>> assert torch.allclose(y[2],torch.sqrt(Cs[0]/Cs[2])/poly.c00*((alpha+1)*(alpha+2)/2+(alpha+2)*(alpha+beta+3)*(xt-1)/2+(alpha+beta+3)*(alpha+beta+4)/2*((xt-1)/2)**2))
>>> coeffs = poly.coeffs(n)
>>> coeffs.shape
torch.Size([5, 5])
>>> coeffs
tensor([[ 1.0000, 0.0000, 0.0000, 0.0000, 0.0000],
[ 2.5526, 1.5213, 0.0000, 0.0000, 0.0000],
[ 5.7016, 7.7823, 2.2653, 0.0000, 0.0000],
[12.4138, 27.3369, 17.4622, 3.3538, 0.0000],
[26.8769, 82.2834, 83.9242, 34.5890, 4.9534]])
>>> xpows = x[...,None]**torch.arange(n+1)
>>> xpows.shape
torch.Size([65536, 5])
>>> yhat = torch.einsum("ij,...j->i...",coeffs,xpows) # generally unstable
>>> yhat.shape
torch.Size([5, 65536])
>>> assert torch.allclose(y,yhat)
>>> yp = poly.deriv(n,x)
>>> yp.shape
torch.Size([5, 65536])
>>> xpowsm1 = x[...,None]**torch.arange(-1,n)
>>> xpowsm1.shape
torch.Size([65536, 5])
>>> yphat = torch.einsum("ij,...j->i...",coeffs*torch.arange(n+1),xpowsm1) # generally unstable
>>> yphat.shape
torch.Size([5, 65536])
>>> assert torch.allclose(yphat,yp)
>>> x = torch.linspace(poly.a,poly.b,6)
>>> n = 8
>>> v = poly.integral(n,x)
>>> v.shape
torch.Size([9, 6])
>>> vhat = torch.ones_like(v)
>>> for i in range(len(x)):
... ttrap = torch.linspace(poly.a,x[i],100000)
... ytrap = poly(n=n,x=ttrap)*poly.weight(ttrap)
... vhat[:,i] = torch.trapezoid(ytrap,ttrap)
>>> assert torch.allclose(vhat,v,atol=1e-5)
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
alpha
|
float
|
parameter \(\alpha>-1\). |
0
|
beta
|
float
|
parameter \(\beta>-1\). |
0
|
loc
|
float
|
weight distribution will be |
-1
|
scale
|
float
|
weight distribution will be |
2
|
Source code in torchorthopolys/orthopolys.py
Gegenbauer
Bases: Jacobi
Orthonormal Gegenbauer polynomials supported on \([-1,1]\) with the weight normalized to be a density function.
These are a special case of the Jacobi polynomials with \(\alpha=\beta\).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
alpha
|
float
|
parameter \(\alpha>-1\). |
0
|
loc
|
float
|
weight distribution will be |
-1
|
scale
|
float
|
weight distribution will be |
2
|
Source code in torchorthopolys/orthopolys.py
Chebyshev1
Bases: Gegenbauer
Orthonormal Chebyshev polynomials of the first kind supported on \([-1,1]\) with the weight normalized to be a density function.
These are a special case of the Gegenbauer polynomials with \(\alpha=-1/2\).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
loc
|
float
|
weight distribution will be |
-1
|
scale
|
float
|
weight distribution will be |
2
|
Source code in torchorthopolys/orthopolys.py
Chebyshev2
Bases: Gegenbauer
Orthonormal Chebyshev polynomials of the second kind supported on \([-1,1]\) with the weight normalized to be a density function.
These are a special case of the Gegenbauer polynomials with \(\alpha=1/2\).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
loc
|
float
|
weight distribution will be |
-1
|
scale
|
float
|
weight distribution will be |
2
|
Source code in torchorthopolys/orthopolys.py
Legendre
Bases: Gegenbauer
Orthonormal Legendre polynomials supported on \([-1,1]\) with the weight normalized to be a density function.
These are a special case of the Gegenbauer polynomials with \(\alpha=0\).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
loc
|
float
|
weight distribution will be |
-1
|
scale
|
float
|
weight distribution will be |
2
|