Special Functions

This module contains different approach to computing the Wigner-d matrices, legendre polynomials and spherical harmonics, as well as some helper functions.

Risbo Recurrence

API

tensossht.specialfunctions.risbo.wignerd(l, beta, sqrts=None)[source]

Wigner-d matrix for order l.

Parameters:
  • l (int) –

  • beta (Union[float, Tensor]) –

  • sqrts (Optional[List[float]]) –

Return type:

Tensor

tensossht.specialfunctions.risbo.recurrence(l, beta, dtype=tf.float32)[source]

Simple Risbo recurrence to compute wigner-d matrices.

This recurrence does not make use of any symmetries.

Example

>>> from pytest import approx
>>> from tensossht.specialfunctions import naive
>>> from tensossht.specialfunctions.risbo import recurrence
>>> R1 = recurrence(l=1, beta=np.pi / 7, dtype=float)
>>> R2 = recurrence(l=2, beta=np.pi / 7, dtype=float)
>>> R2R1 = tf.tensordot(R2, R1, axes=[[2, 3], [0, 1]])
>>> np.array(R2R1)  == approx(naive.wignerd(2, beta=np.pi / 7).astype(float))
True
>>> R3 = recurrence(l=3, beta=np.pi / 7, dtype=float)
>>> R3R2R1 = tf.tensordot(R3, R2R1, axes=[[2, 3], [0, 1]])
>>> np.array(R3R2R1)  == approx(naive.wignerd(3, beta=np.pi / 7).astype(float))
True
Parameters:
  • l (int) –

  • beta (float) –

  • dtype (Union[str, Type]) –

Return type:

Tensor

tensossht.specialfunctions.risbo.sparse_recurrence(l, beta, sqrts=None, dtype=tf.float32)[source]

Risbo recurrense using sparse tensors.

Parameters:
  • l (int) –

  • beta (float) –

  • sqrts (Optional[List[float]]) –

  • dtype (Union[str, Type]) –

Return type:

Tuple[SparseTensor, SparseTensor]

tensossht.specialfunctions.risbo.straightforward(l, m1, m2, beta, sqrts=None)[source]
Parameters:
  • l (int) –

  • m1 (int) –

  • m2 (int) –

  • beta (float) –

  • sqrts (Optional[List[float]]) –

Return type:

float

tensossht.specialfunctions.risbo.initial(l, beta)[source]

D-matrices for L=0 and L=1.

Example

>>> from pytest import approx
>>> from tensossht.specialfunctions import naive
>>> from tensossht.specialfunctions.risbo import initial
>>> np.array(initial(0, np.pi / 2)) == approx(naive.wignerd(0, 0, 0, np.pi / 2))
True
>>> np.array(initial(0, np.pi / 3)) == approx(naive.wignerd(0, 0, 0, np.pi / 3))
True
>>> np.array(initial(1, np.pi / 7)) == approx(
...     naive.wignerd(1, beta=np.pi / 7).astype(float)
... )
True
Parameters:
  • l (int) –

  • beta (Union[float, ndarray, Tensor]) –

Return type:

Tensor

Kostelec Recurrence

Implementation of the recurrence from [Kostelec, Rockmore (2008)].

API

tensossht.specialfunctions.kostelec.legendre(beta, lmax=None, lmin=0, mmin=0, mmax=None, labels=None, scaled=True)[source]

Legendre polynomials via the Kostelec recurrence.

See [Kostelec, Rockmore (2008)], equations 4.6, 4.10, and 4.11. Specifically, They are implemented here with \(m'=0\), reproduced and simplified below:

\[ \begin{align}\begin{aligned}d^j_{j0}(\beta) = \sqrt{\frac{(2j)!}{j!^2}} 2^{-j}\sin^j\beta\\\tilde{d}^j_{m0} = \sqrt{\frac{2}{3j + 1}} d^j_{m0}\\\tilde{d}^{j+1}_{m0} = \sqrt{\frac{(2j + 3)(2j+1)}{(j + 1)^2 - m^2}}\cos\beta \tilde{d}^j_{m0} - \sqrt{\frac{(2j + 3)(j^2 - m^2)}{(2j - 1)(j + 1)^2 - m^2}} \tilde{d}^{j-1}_{m0}\end{aligned}\end{align} \]
Parameters:
  • beta (Union[float, Tensor]) –

  • lmax (Optional[int]) –

  • lmin (int) –

  • mmin (int) –

  • mmax (Optional[int]) –

  • labels (Optional[Union[ndarray, Tensor]]) –

  • scaled (bool) –

Return type:

Tensor

tensossht.specialfunctions.kostelec.wignerd(beta, *, labels=None, lmax=None, lmin=0, mmin=None, mmax=None, mpmin=None, mpmax=None, scaled=True)[source]
Parameters:
  • beta (Union[float, Tensor]) –

  • labels (Optional[Tensor]) –

  • lmax (Optional[int]) –

  • lmin (int) –

  • mmin (Optional[int]) –

  • mmax (Optional[int]) –

  • mpmin (Optional[int]) –

  • mpmax (Optional[int]) –

  • scaled (bool) –

Return type:

Tensor

tensossht.specialfunctions.kostelec.logfact(n, dtype=tf.float32)[source]

Log of factorial 0 <= i <= n.

Example

>>> from tensossht.specialfunctions.kostelec import logfact
>>> tf.exp(logfact(5)).numpy().astype(float).round(2)
array([  1.,   1.,   2.,   6.,  24., 120.])
Parameters:
  • n (Union[int, Tensor]) –

  • dtype (Union[str, DType]) –

Return type:

Tensor

Trapani Recurrence

Implementation of the recurrence from [Trapani, Navaza (2006)].

API

tensossht.specialfunctions.trapani.straightforward(l, m1, m2, sqrts=None)[source]

Straightforward implementation of the Trapani recuurence.

Parameters:
  • l (int) –

  • m1 (int) –

  • m2 (int) –

  • sqrts (Optional[ndarray]) –

Return type:

float

tensossht.specialfunctions.trapani.deltas(*, labels=None, lmax=None, lmin=0, mmin=None, mmax=None, mpmin=None, mpmax=None, scaled=True, dtype=tf.float32)[source]
Parameters:
  • labels (Optional[ndarray]) –

  • lmax (Optional[int]) –

  • lmin (int) –

  • mmin (Optional[int]) –

  • mmax (Optional[int]) –

  • mpmin (Optional[int]) –

  • mpmax (Optional[int]) –

  • scaled (bool) –

  • dtype (Union[str, DType, dtype]) –

Return type:

ndarray

tensossht.specialfunctions.trapani.full_tensor(compressed, lmin=0, lmax=None, dtype=None)[source]

Converts compressed tensors to the full 2L by 2L tensor.

More explicitly, it creates a tensor where all m, m’ components are present where \(l_{\min} \leq |m| \leq l_{\max}\).

compressed sensor needs not correspond to an L within that range. The resulting tensor will be padded with zeros for out-of-range values.

Parameters:
  • compressed (ndarray) –

  • lmin (int) –

  • lmax (Optional[int]) –

  • dtype (Optional[Union[Type, str]]) –

Return type:

ndarray

tensossht.specialfunctions.trapani.symmetrized_index(l, m1, m2, factor=1)[source]

Computes index and factor to go from compressed results to full tensor.

Only 0 <= m2 <= m1 are represented in the recursion. Given l, and any general m1 and m2, this funtion outputs the index and factor needed to recover the full symmetrized wignerd value.

Example

Evidently, this function does not do much when it tries to access those elements that are explictly present in the compressed form:

>>> from tensossht.specialfunctions.trapani import (
...     recursion_tensor as R, symmetrized_index, linear_index
... )
>>> compressed = R(5) @ R(4) @ R(3) @ R(2) @ R(1) @ R(0)
>>> index, factor = symmetrized_index(5, 4, 3)
>>> factor == 1
True
>>> index == linear_index(4, 3)
True

We can check against the wigner-d function that the correct factor was recovered.

>>> from pytest import approx
>>> from tensossht.specialfunctions import naive
>>> index, factor = symmetrized_index(5, -4, -3)
>>> index, factor
(13, -1)
>>> float(compressed[index] * factor)== approx(naive.wignerd(5, -4, -3))
True
Parameters:
  • l (int) –

  • m1 (int) –

  • m2 (int) –

  • factor (int) –

Return type:

Tuple[int, int]

tensossht.specialfunctions.trapani.linear_index(m1, m2)[source]

Linear index for a given (m1, m2) triplet.

Parameters:
  • m1 (int) –

  • m2 (int) –

Return type:

int

tensossht.specialfunctions.trapani.ncoeffs(l)[source]

Number of coefficients with 0 <= m_1 <= m_2 <= l.

Parameters:

l (int) –

Return type:

int

tensossht.specialfunctions.trapani.order_from_ncoeffs(n)[source]

Computes l for a given number of coefficients.

In practice, this is the inverse of ncoeffs.

Example

>>> from tensossht.specialfunctions.trapani import order_from_ncoeffs, ncoeffs
>>> order_from_ncoeffs(ncoeffs(1))
1
>>> order_from_ncoeffs(ncoeffs(2))
2
>>> order_from_ncoeffs(ncoeffs(20))
20
Parameters:

n (int) –

Return type:

int

tensossht.specialfunctions.trapani.delta_ll0(llabels, lmax=None, sqrts=None, dtype=tf.float32)[source]
Parameters:
  • llabels (Tensor) –

  • lmax (Optional[int]) –

  • sqrts (Optional[Tensor]) –

  • dtype (Union[str, DType, dtype]) –

Return type:

ndarray

tensossht.specialfunctions.trapani.delta_llm(llabels, mlabels, initial=None, sqrts=None, dtype=tf.float32)[source]
Parameters:
  • llabels (ndarray) –

  • mlabels (ndarray) –

  • initial (Optional[ndarray]) –

  • sqrts (Optional[ndarray]) –

  • dtype (Union[str, DType, dtype]) –

Return type:

ndarray

tensossht.specialfunctions.trapani._delta_lmmp_impl(labels, initial, sqrts)[source]

Implements Eq 11 of the Trapani recurrence pyramid.

Example

First, we ensure the recurrence does not act on (l, l, m) terms

>>> from pytest import approx
>>> from tensossht import wignerd_labels
>>> from tensossht.specialfunctions.trapani import _delta_lmmp_impl, delta_llm
>>> labels = wignerd_labels(8)
>>> labels = tf.boolean_mask(labels, labels[0] == labels[1], axis=1)
>>> llm = delta_llm(labels[0], labels[2], dtype=tf.float64)
>>> sqrts = tf.sqrt(tf.range(2 * labels.shape[1] + 2, dtype=tf.float64))
>>> lmmp = _delta_lmmp_impl(labels, llm, sqrts)
>>> lmmp.numpy() == approx(llm.numpy())
True

Now we check the recurrence with only one term against the naive, multi-precision implementation:

>>> from tensossht.specialfunctions.naive import wignerd
>>> labels = wignerd_labels(8)
>>> labels = tf.boolean_mask(labels, labels[0] == labels[1] + 1, axis=1)
>>> llm = delta_llm(labels[0], labels[2], dtype=tf.float64)
>>> lmmp = _delta_lmmp_impl(labels, llm, sqrts)
>>> expected = [wignerd(*labels[:, i].numpy()) for i in range(labels.shape[1])]
>>> lmmp.numpy() == approx(expected)
True

Finally, we check the full recurrence:

>>> labels = wignerd_labels(8)
>>> llm = delta_llm(labels[0], labels[2], dtype=tf.float64)
>>> lmmp = _delta_lmmp_impl(labels, llm, sqrts)
>>> expected = [wignerd(*labels[:, i].numpy()) for i in range(labels.shape[1])]
>>> lmmp.numpy() == approx(expected)
True
Parameters:
  • labels (ndarray) –

  • initial (ndarray) –

  • sqrts (ndarray) –

Return type:

ndarray

Naive brute-force implementations

These are straightforward implementation of the special functions. They are only useful for testing and as definitions.

API

tensossht.specialfunctions.naive.wignerd(l, m1=None, m2=None, beta=None, precision=None)[source]

Straight-forward Wigner d-matrix implementation.

Relies on arbirtrary precision floating points for numerical stability. Safe but slow.

\[d_{mm'}^l(\beta) = \sqrt{!(l + m)!(l - m)!(l + m')!(l - m')} \sum_s \frac{ (-1)^{m - m' + s} \left(\cos\frac{\beta}{2}\right)^{2(l - s) + m' - m} \left(\sin\frac{\beta}{2}\right)^{2s + m - m'} }{!(l - m - s)!(l + m' - s)!(s + m - m')!k}\]

With \(s\) such that the terms in the factorial are positive or null:

\[ \begin{align}\begin{aligned}l - m &\geq s\\l + m' &\geq s\\s &\geq 0\\s &\geq m' - m\end{aligned}\end{align} \]
Parameters:
  • l (int) –

  • m1 (Union[None, Sequence, int]) –

  • m2 (Union[None, Sequence, int]) –

  • beta (Optional[float]) –

  • precision (Optional[int]) –

Return type:

ndarray

tensossht.specialfunctions.naive.legendre(l, m, x)[source]

Associated legendre functions up to l = 4 and m = 4.

As given by wikipedia.

Parameters:
  • l (int) –

  • m (int) –

  • x (float) –

Return type:

float

tensossht.specialfunctions.naive.spherical_harmonics(theta, phi, l, m)[source]

Spherical harmonics up to \((l=4, m=4)\).

Example

>>> from tensossht.specialfunctions.naive import spherical_harmonics
>>> np.round(spherical_harmonics(np.pi / 3, np.pi / 2, 0, 0), 8)
(0.28209479+0j)
>>> np.round(spherical_harmonics(np.pi / 3, np.pi / 2, 1, 0), 8)
(0.24430126+0j)
>>> np.round(spherical_harmonics(np.pi / 3, np.pi / 2, 1, 1), 8)
(-0-0.29920671j)
>>> np.round(spherical_harmonics(np.pi / 3, np.pi / 2, 2, 0), 8)
(-0.07884789+0j)
>>> np.round(spherical_harmonics(np.pi / 3, np.pi / 2, 2, 1), 8)
(-0-0.33452327j)
Parameters:
  • theta (float) –

  • phi (float) –

  • l (int) –

  • m (int) –

Return type:

float

tensossht.specialfunctions.naive.spin_spherical_harmonics(theta, phi, lmax, lmin=0, mmax=None, mmin=None, smax=None, smin=None, spin=None, precision=None, compact_spin=None)[source]

Spin-weighted spherical harmonics the naive way.

Examples

>>> from pytest import approx
>>> from tensossht import spherical_harmonics
>>> from tensossht.specialfunctions import naive
>>> theta = tf.range(0, 1, 0.2)
>>> phi = tf.range(0, 1, 0.2)
>>> expected = spherical_harmonics(theta, phi, lmax=3)
>>> actual = naive.spin_spherical_harmonics(theta, phi, lmax=3, smax=0, smin=0)
>>> assert tf.reduce_all(tf.math.abs(actual - expected) < 1e-6)
Parameters:
  • theta (Tensor) –

  • phi (Tensor) –

  • lmax (int) –

  • lmin (int) –

  • mmax (Optional[int]) –

  • mmin (Optional[int]) –

  • smax (Optional[int]) –

  • smin (Optional[int]) –

  • spin (Optional[int]) –

  • precision (Optional[int]) –

  • compact_spin (Optional[bool]) –

Return type:

Tensor

tensossht.specialfunctions.naive._spin_spherical_harmonics(theta, phi, l, m, s, precision=None)[source]

Spin-weighted spherical_harmonics.

Examples

Comparison against spin-zero spherical harmonics.

>>> from pytest import approx
>>> from tensossht.specialfunctions.naive import (
...     _spin_spherical_harmonics, spherical_harmonics
... )
>>> for i in range(10):
...     l = np.random.randint(5)
...     m = np.random.randint(-l, l + 1)
...     theta, phi = np.pi * np.random.random(2)
...     expected = spherical_harmonics(theta, phi, l, m)
...     actual = _spin_spherical_harmonics(theta, phi, l, m, 0)
...     assert actual == approx(expected)

Wikipedia’s spin=1 harmonics

>>> for i in range(10):
...     theta, phi = np.pi * np.random.random(2)
...     expected = np.sqrt(3 / (8 * np.pi)) * np.sin(theta)
...     actual = _spin_spherical_harmonics(theta, phi, 1, 0, 1)
...     assert actual == approx(expected)
>>> for i in range(10):
...     theta, phi = np.pi * np.random.random(2)
...     factor = -np.sqrt(3 / (16 * np.pi))
...     expected = factor * (1 - np.cos(theta)) * np.exp(1j * phi)
...     actual = _spin_spherical_harmonics(theta, phi, 1, 1, 1)
...     assert actual == approx(expected)
>>> for i in range(10):
...     theta, phi = np.pi * np.random.random(2)
...     factor = -np.sqrt(3 / (16 * np.pi))
...     expected = factor * (1 + np.cos(theta)) * np.exp(-1j * phi)
...     actual = _spin_spherical_harmonics(theta, phi, 1, -1, 1)
...     assert actual == approx(expected)
Parameters:
  • theta (float) –

  • phi (float) –

  • l (int) –

  • m (int) –

  • s (int) –

  • precision (Optional[int]) –

Return type:

float

Other functions and data-structures

tensossht.specialfunctions.legendre(beta, *args, method=Methods.KOSTELEC, **kwargs)[source]

Legendre polynomial using one of several methods or recurrence.

Argument and keywords are passed on to the legendre function from the relevant module.

Example

>>> from tensossht.specialfunctions import legendre, Methods
>>> legpol = legendre(beta=0.4, lmax=4, method=Methods.KOSTELEC)
>>> legpol.numpy().round(4)
array([ 1.    ,  0.9211, -0.2754,  0.7725, -0.4393,  0.0929,  0.5719,
       -0.5466,  0.1913, -0.033 ], dtype=float32)
Parameters:
  • beta (Union[float, List[float], Tensor]) –

  • method (Methods) –

Return type:

Tensor

tensossht.specialfunctions.spherical_harmonics(theta, phi, lmax=None, lmin=0, mmin=None, mmax=None, labels=None, method=Methods.KOSTELEC)[source]

Spherical harmonics as obtained from the legendre polynomials:

\[Y_{lm}(\theta, \phi) = \sqrt{\frac{2l + 1}{4\pi}\frac{(l - m)!}{(l + m)!}} P_l^m(\cos{\theta}) e^{\imath m\phi}\]

Example

We can compute the spherical harmonics over a given sampling grid:

>>> from tensossht import sampling, spherical_harmonics
>>> lmax = 5
>>> grid = sampling.equiangular(lmax=lmax, dtype=tf.float64).numpy()
>>> theta, phi = grid[0].flatten(), grid[1].flatten()
>>> sph = spherical_harmonics(theta, phi, lmax=lmax)
>>> sph.ndim
2

The first dimension corresponds to the number of points on the grid:

>>> assert sph.shape[0] == len(theta)

The second dimension corresponds to each spherical harmonic, up to lmax=5 in our example. We reconstruct the matrix of (l, m) labels below:

>>> from tensossht import legendre_labels
>>> labels = legendre_labels(lmax=lmax, mmin=None)
>>> assert sph.shape[1] == labels.shape[1]

We can verify that first harmonic (l=0, m=0) is equal to \(\frac{1}{2\sqrt{\pi}}\):

>>> from pytest import approx
>>> tuple(labels[:, 0].numpy())
(0, 0)
>>> assert sph[:, 0].numpy() == approx(0.5 / np.sqrt(np.pi))

More generally, we can compare to the hard-coded spherical harmonics from tensossht.specialfunctions.naive:

>>> from tensossht.specialfunctions import naive
>>> for i, (l, m) in enumerate(labels[:15].numpy().T):
...     expected = [
...         naive.spherical_harmonics(t, p, l, m)
...         for t, p in zip(theta, phi)
...     ]
...     assert sph[:, i].numpy() == approx(expected)
Parameters:
  • theta (Tensor) –

  • phi (Tensor) –

  • lmax (Optional[int]) –

  • lmin (int) –

  • mmin (Optional[int]) –

  • mmax (Optional[int]) –

  • labels (Optional[Union[ndarray, Tensor]]) –

  • method (Methods) –

Return type:

Tensor

tensossht.specialfunctions.to_matrix_coefficients(coefficients, lmax, lmin=0, mmax=None, mmin=None, fill_value=0, coeff_dim=0, l_dim=0, m_dim=1)[source]

Converts compressed coefficients to matrix form.

Example

We can convert the labels themselves from compressed to matrix form:

>>> from tensossht import legendre_labels
>>> lmax, lmin, mmax, mmin = 4, 1, 3, -2
>>> labels = legendre_labels(lmax=lmax, lmin=lmin, mmax=mmax, mmin=mmin)
>>> labels
<tf.Tensor: shape=(2, 14), dtype=int32, numpy=
array([[ 1,  1,  1,  2,  2,  2,  2,  2,  3,  3,  3,  3,  3,  3],
       [-1,  0,  1, -2, -1,  0,  1,  2, -2, -1,  0,  1,  2,  3]],
      dtype=int32)>

The array above uses memory optimally in that each element is used. However, it can be difficult to address directly an element of a given degree and order. The conversion provides a matrix form with simpler addressing at the cost of greater memory usages.

>>> from tensossht import to_matrix_coefficients
>>> to_matrix_coefficients(
...     labels, lmax, lmin, mmax, mmin,
...     coeff_dim=-1, fill_value=100, l_dim=-2, m_dim=-1,
... )
<tf.Tensor: shape=(2, 3, 6), dtype=int32, numpy=
array([[[100,   1,   1,   1, 100, 100],
        [  2,   2,   2,   2,   2, 100],
        [  3,   3,   3,   3,   3,   3]],

       [[100,  -1,   0,   1, 100, 100],
        [ -2,  -1,   0,   1,   2, 100],
        [ -2,  -1,   0,   1,   2,   3]]], dtype=int32)>

The l’s vary across columns, whereas the m’s varie across rows. The two indices are now separate dimensions.

Parameters:
  • coefficients (Tensor) –

  • lmax (int) –

  • lmin (int) –

  • mmax (Optional[int]) –

  • mmin (Optional[int]) –

  • fill_value (Union[int, float, complex, Tensor, Variable]) –

  • coeff_dim (int) –

  • l_dim (int) –

  • m_dim (int) –

Return type:

Tensor

tensossht.specialfunctions.to_compressed_coefficients(matrix, lmax=None, lmin=None, mmax=None, mmin=None, labels=None, l_dim=0, m_dim=1, coeff_dim=0)[source]

Converts compressed coefficients to matrix form.

Example

We can convert the labels themselves from matrix to compressed form. The matrix below is 2 by l by m. The matrix contains unnecessary extra elements, initialized for show to 100 below. However, it is easy to address a specific \((l, m)\). On the other hand, the compressed form is optimal in terms of memory consumption. However, addressing a given \((l, m)\) is not trivial.

>>> from tensossht import to_compressed_coefficients, legendre_labels
>>> lmax, lmin, mmax, mmin = 4, 1, 3, -2
>>> matrix = tf.constant(
...     # order l
...     [[[100,   1,   1,   1, 100, 100],
...       [  2,   2,   2,   2,   2, 100],
...       [  3,   3,   3,   3,   3,   3]],
...     # degree m
...      [[100,  -1,   0,   1, 100, 100],
...       [ -2,  -1,   0,   1,   2, 100],
...       [ -2,  -1,   0,   1,   2,   3]]]
... )
>>> compressed = to_compressed_coefficients(
...     matrix, lmax, lmin, mmax, mmin, coeff_dim=-1, l_dim=-2, m_dim=-1
... )
>>> labels = legendre_labels(lmax=lmax, lmin=lmin, mmax=mmax, mmin=mmin)
>>> assert (compressed == labels).numpy().all()
Parameters:
  • matrix (Tensor) –

  • lmax (Optional[int]) –

  • lmin (Optional[int]) –

  • mmax (Optional[int]) –

  • mmin (Optional[int]) –

  • labels (Optional[Tensor]) –

  • l_dim (int) –

  • m_dim (int) –

  • coeff_dim (int) –

Return type:

Tensor

tensossht.specialfunctions.legendre_lsum(data, lmax, lmin=0, mmax=None, mmin=0, axis=<tf.Tensor: shape=(), dtype=int32, numpy=0>, constant_values=0)[source]

Sums coefficients over L.

Assumes the data is in the same order as given by legendre_labels() and performs a reduction over l.

Example

The point is that the data for any given all only contains elements satisfying the conditions \(-l \leq m \leq l\) and \(m_\mathrm{min} \leq m \leq m_\mathrm{max}\). Elements outside this range default to zero.

>>> from tensossht import legendre_labels
>>> from tensossht.specialfunctions import legendre_lsum
>>> lmax, lmin, mmax, mmin = 8, 2, 4, -3
>>> labels = legendre_labels(lmax=lmax, lmin=lmin, mmax=mmax, mmin=mmin)
>>> legendre_lsum(labels[0], lmax=lmax, lmin=lmin, mmax=mmax, mmin=mmin).numpy()
array([25, 27, 27, 27, 27, 27, 25, 22], dtype=int32)

Above, the first and last two items are those for which some coefficients defaulted to zero.

The summation works for any number of dimensions, as long as the \((l, m)\) axis is provided (defaults to zero).

>>> repeats = tf.tile(labels[0][None, :], (2, 1))
>>> legendre_lsum(
...     repeats, lmax=lmax, lmin=lmin, mmax=mmax, mmin=mmin, axis=1
... ).numpy()
array([[25, 27, 27, 27, 27, 27, 25, 22],
       [25, 27, 27, 27, 27, 27, 25, 22]], dtype=int32)
>>> legendre_lsum(
...     tf.transpose(repeats),
...     lmax=lmax,
...     lmin=lmin,
...     mmax=mmax,
...     mmin=mmin,
...     axis=0
... ).numpy()
array([[25, 25],
       [27, 27],
       [27, 27],
       [27, 27],
       [27, 27],
       [27, 27],
       [25, 25],
       [22, 22]], dtype=int32)
Parameters:
  • data (Tensor) –

  • lmax (int) –

  • lmin (int) –

  • mmax (Optional[int]) –

  • mmin (Optional[int]) –

  • axis (Union[int, Tensor]) –

Return type:

Tensor

class tensossht.specialfunctions.Methods(value)[source]

An enumeration.