freealg.AlgebraicForm.atoms#

AlgebraicForm.atoms(eta=1e-06, tol=1e-12, real_tol=None, w_tol=1e-10, merge_tol=1e-08)#

Detect atom locations and weights of distribution

Parameters:
etafloat, default=1e-6

Small imaginary part used to probe the pole strength.

tolfloat, default=1e-12

Tolerance for trimming polynomial coefficients.

real_tolfloat or None, default=None

Tolerance for treating a complex root as real. If None, uses 1e3*tol.

w_tolfloat, default=1e-10

Minimum atom weight to report.

merge_tolfloat, default=1e-8

Merge roots whose real parts differ by at most this tolerance.

Returns:
atomslist of (float, float)

List of tuples of the form (atom_loc, atom_w). Locations are real numbers and weights are nonnegative.

Notes

This routine uses the necessary condition for a finite pole

\[a_s(z_0) = 0,\]

where \(a_s(z)\) is the leading coefficient of \(P\) in powers of \(m\). Candidate atom locations are the (nearly) real roots of \(a_s(z)\). The atom weight is estimated numerically from the Stieltjes transform as

\[w = \eta \, \Im(m(z_0 + i \eta)),\]

which follows from \(m(z) \sim -w/(z - z_0)\) near an atom at \(z_0\).

Examples

>>> # Create a distribution with two bulks
>>> from freealg.distributions import CompoundFreePoisson
>>> cfp = CompoundFreePoisson(t=[2.0,  5.5], w=[0.75, 0.25],
...                           lam=0.1)

>>> # Create AlgebraicForm and fit the distribution
>>> from freealg import AlgebraicForm
>>> af = AlgebraicForm(cfp)
>>> af.fit(deg_m=3, deg_z=1)

>>> # Estimate the atoms (using the fitted polynomial). This
>>> # distribution has an atom at x=0 with 90% mass of the total
>>> # spectral density.
>>> atoms = af.atoms()
>>> print(atoms)
 [(1.2538385955639516e-16, 0.9000000001406558)]