<jupyter_start><jupyter_text>This Notebook demonstrates the package ``structure_factor`` on the Ginibre ensemble.  - Running time --- 759.3946590423584 seconds ---<jupyter_code>import time
start_all = time.time()<jupyter_output><empty_output><jupyter_text>We use the Ginibre point process as a running example. It is convenient, since its pair correlation function, structure factor, and hyperuniformity class are analytically known.You can simply change the point process used, by modifying the ``PointPattern``, then run the notebook on the new point process.  1- Installation If the package is not already installed/updated on your local machine you can simply use the following first-line/second for the installation/update.<jupyter_code>!pip install structure-factor
# !pip install structure-factor --upgrade<jupyter_output><empty_output><jupyter_text>2- Create a PointPattern object  To create an object of type ``PointPattern`` from a point process, we need a sample of points, the observation window (typically a ``BallWindow`` or  a ``BoxWindow``), and the intensity of the point process (optional). A ``PointPattern`` from the Poisson, Thomas, Ginibre, or KLY point process could be created using the module ``point_process``. For more details, we refer to the documentation of this project https://for-a-few-dpps-more.github.io/structure-factor/.In what follows we will be loading a Ginibre PointPattern of 10^4 points (instead of creating one) using ``load_data`` from the module ``data``.<jupyter_code># Load Ginibre PointPattern 
from structure_factor.point_processes import GinibrePointProcess
from structure_factor.data import load_data

# Load
point_pattern_ball = load_data.load_ginibre()
# Plot
point_pattern_ball.plot()
# Or create a Ginibre PointPattern as follows

#from structure_factor.point_pattern import PointPattern
#from structure_factor.point_processes import GinibrePointProcess
#from structure_factor.spatial_windows import BallWindow

#point_process = GinibrePointProcess()

#window = BallWindow(center=[0, 0], radius=20)
#points = point_process.generate_sample(window=window)
#point_pattern_ball = PointPattern(points=points, window=window, intensity=point_process.intensity)<jupyter_output><empty_output><jupyter_text>The exact structure factor and the pair correlation function of the Ginibre point process are known so we will use them to compare with the estimated values.<jupyter_code>from structure_factor.point_processes import GinibrePointProcess

point_process = GinibrePointProcess()
exact_sf = point_process.structure_factor
exact_pcf = point_process.pair_correlation_function<jupyter_output><empty_output><jupyter_text>3- Approximate the structure factor Actually, the package gathers estimators of the structure factor for:        1- stationary point processes,         2- stationary and isotropic point processes.  3.1- Estimators assuming stationarity The estimators that assume the stationarity of the point process, only apply to a ``PointPattern`` with an observation ``BoxWindow``.As ``point_pattern_ball`` has a ``BallWindow`` we will first restrict it to a new ``PointPattern`` with ``BoxWindow``.<jupyter_code># Restrict to a BoxWindow
from structure_factor.spatial_windows import BoxWindow
import numpy as np

l = point_pattern_ball.window.radius*2/np.sqrt(2) # length side of the BoxWindow
box_window = BoxWindow(bounds=[[-l/2, l/2], [-l/2, l/2]]) # BoxWindow
point_pattern_box = point_pattern_ball.restrict_to_window(box_window) # Restrict to box_window
# Plot
point_pattern_box.plot()<jupyter_output><empty_output><jupyter_text>As we have the adequate ``PointPattern`` we will initialize StructureFactor and then use the estimators progressively.<jupyter_code>from structure_factor.structure_factor import StructureFactor

sf = StructureFactor(point_pattern_box)<jupyter_output><empty_output><jupyter_text>3.1.1- Scattering intensity The scattering intensity $\widehat{S}_{\mathrm{SI}}$ is an estimator of the structure factor $S$ of a stationary point process.It can be evaluated on arbitrary wavevectors, or allowed wavevectors to reduce the bias.It has also 2 debiased versions directly/undirectly.It is a particular case of the tapered estimator $\widehat{S}_{\mathrm{T}}$ using Bartlett's taper.<jupyter_code># Scattering intensity on arbitrary wavevectors
import numpy as np

# Construct a grid of wavevectors
k_max=8 # Threshold on the maximum wavenumber
x = np.linspace(0, k_max, 200)
x = x[x != 0]
X, Y = np.meshgrid(x, x)
k = np.column_stack((X.ravel(), Y.ravel())) # Wavevectors

# Scattering intensity on k 
k, s_si_k = sf.scattering_intensity(k=k, debiased=False )

# Plot
import matplotlib.pyplot as plt

fig, axis = plt.subplots(figsize=(7,6))
sf.plot_non_isotropic_estimator(k, s_si_k, 
                                axes=axis,
                                plot_type="radial", 
                                exact_sf=exact_sf,
                                error_bar=True, bins=60,
                                scale="log", 
                                rasterized=True, 
                                label=r"$\widehat{S}$", 
                                # file_name="s_si.pdf" 
                                      )<jupyter_output><empty_output><jupyter_text>The asymptotic bias of $\widehat{S}_{\mathrm{SI}}$ at small non allowed wavenumber $k$ is visible.To deal with this bias we can use one of the following three debiased versions.<jupyter_code># Scattering intensity on allowed wavevectors

k_max=8 # Threshold on the maximum wavenumber 
allowed_k, s_si_allowed_k = sf.scattering_intensity(k_max=k_max)

# Plot
sf.plot_non_isotropic_estimator(allowed_k, s_si_allowed_k, 
                                       plot_type="all",   
                                       exact_sf=exact_sf, 
                                       error_bar=True, bins=60,
                                       label=r"$\widehat{S}$",
                                      # file_name="ginibre_s_si.pdf" 
                                      )
# Scattering intensity directly debiased on arbitrary wavevectors

# Construct grid of wavevectors
k_max=8 # Threshold on the maximum wavenumber
x = np.linspace(-k_max, k_max, 17**2)
x = x[x != 0]
X, Y = np.meshgrid(x, x)
k = np.column_stack((X.ravel(), Y.ravel())) # Wavevectors
# Scattering intensity on k 
k, s_si_dd = sf.scattering_intensity(k=k, debiased=True,  direct=True)

# Plot
import matplotlib.pyplot as plt

sf.plot_non_isotropic_estimator(k, s_si_dd,  
                                       plot_type="all", 
                                       exact_sf=exact_sf, 
                                       error_bar=True, bins=80, 
                                       scale="log",
                                       rasterized=True, 
                                       label=r"$\widehat{S}$")
# Scattering intensity undirectly debiased on arbitrary wavevectors

# Construct grid of wavevectors
k_max=8 # Threshold on the maximum wavenumber
x = np.linspace(0, k_max, 17**2)
x = x[x != 0]
X, Y = np.meshgrid(x, x)
k = np.column_stack((X.ravel(), Y.ravel())) # Wavevectors
# Scattering intensity on k 
k, s_si_ud = sf.scattering_intensity(k=k, debiased=True, direct=False)

# Plot
import matplotlib.pyplot as plt

sf.plot_non_isotropic_estimator(k, s_si_ud, 
                                #positive=True, 
                                plot_type="radial",
                                exact_sf=exact_sf, 
                                error_bar=True, bins=80, 
                                scale="log", 
                                rasterized=True,
                                label=r"$\widehat{S}$")<jupyter_output><empty_output><jupyter_text>We can see a few negative values, resulting in large inaccuracies in our log-log scale.You can add ``positive=True`` to the plot function to consider only positive values.  3.1.2- Tapered estimator with a single sine taper The tapered estimator $\widehat{S}_{\mathrm{T}}$ is an estimator of the structure factor $S$ of a stationary point process depending on a taper function.It has 2 debiased versions $\widehat{S}_{\mathrm{DDT}}$, and $\widehat{S}_{\mathrm{UDT}}$ (directly/undirectly).In what follows, we will be using the first taper of the family of sinusoidal tapers available in the module ``tapers``.To use a new taper follow the example in the documentation.<jupyter_code># Tapered estimator
from structure_factor.tapers import SineTaper
 
k_max = 8 # Threshold on the maximum wavenumber
x = np.linspace(0, k_max, 250)
x = x[x != 0]
X, Y = np.meshgrid(x, x)
k = np.column_stack((X.ravel(), Y.ravel()))

# First taper of the family of sinusoidal tapers
p = [1, 1]
tapers = [SineTaper(p)]

# Tapered estimator
k, s_t = sf.tapered_estimator(k, tapers=tapers, debiased=False)

# Plot
sf.plot_non_isotropic_estimator(k, s_t, 
                                plot_type="radial", 
                                exact_sf=exact_sf, 
                                error_bar=True, bins=80, 
                                scale="log",
                                rasterized=True, 
                                label=r"$\widehat{S}$")<jupyter_output><empty_output><jupyter_text>The asymptotic bias of $\widehat{S}_{\mathrm{T}}$ at small wavenumbers $\|k\|_2$ is visible. To deal with this bias we can use one of the following two debiased versions.<jupyter_code># Directly debiased tapered estimator

from structure_factor.tapers import SineTaper
 
k_max = 8 # Threshold on the maximum wavenumber
x = np.linspace(0, k_max, 250)
x = x[x != 0]
X, Y = np.meshgrid(x, x)
k = np.column_stack((X.ravel(), Y.ravel()))

# First taper of the family of sinusoidal tapers
p = [1, 1]
tapers = [SineTaper(p)]

# Tapered estimator
k, s_ddt = sf.tapered_estimator(k, tapers=tapers, debiased=True, direct=True)

# Plot
sf.plot_non_isotropic_estimator(k, s_ddt, 
                                plot_type="radial", 
                                exact_sf=exact_sf, 
                                error_bar=True, bins=80, 
                                scale="log", 
                                rasterized=True, 
                                label=r"$\widehat{S}$")
# Undirectly debiased tapered estimator
from structure_factor.tapers import SineTaper

# Wavevectors
k_max = 8 # Threshold on the maximum wavenumber
x = np.linspace(0, k_max, 250)
x = x[x != 0]
X, Y = np.meshgrid(x, x)
k = np.column_stack((X.ravel(), Y.ravel()))

# First taper of the family of sinusoidal tapers
p = [1, 1]
tapers = [SineTaper(p)]

# Tapered estimator
k, s_udt = sf.tapered_estimator(k, tapers=tapers, debiased=True, direct=False)

# Plot
sf.plot_non_isotropic_estimator(k, s_udt, 
                                positive=True,
                                plot_type="radial", 
                                exact_sf=exact_sf, 
                                error_bar=True, bins=80, 
                                scale="log",
                                rasterized=True, 
                                label=r"$\widehat{S}$")<jupyter_output><empty_output><jupyter_text>3.1.3- Multitapered estimator The multitapered estimator $\widehat{S}_{\mathrm{MT}}$ is an estimator of the structure factor $S$ of a stationary point process depending on a family of tapers. It is a generalization of the tapered estimator $\widehat{S}_{\mathrm{T}}$.It has 2 debiased versions $\widehat{S}_{\mathrm{DDMT}}$, and $\widehat{S}_{\mathrm{UDMT}}$ (directly/undirectly).In what follows, we will be using the first 4 tapers of the family of sinusoidal tapers available in the module ``tapers``.To use a new family of tapers, follow the example present in the documentation.<jupyter_code># Multitapered estimator
from structure_factor.tapers import SineTaper
 
# Wavevectors
k_max = 8 # Threshold on the maximum wavenumber
x = np.linspace(0, k_max, 200)
x = x[x != 0]
X, Y = np.meshgrid(x, x)
k = np.column_stack((X.ravel(), Y.ravel()))

# First 4 tapers of the family of sinusoidal tapers
from structure_factor.tapers import multi_sinetaper_grid
tapers = multi_sinetaper_grid(d=2, p_component_max=2)

# Scaled multitapered periodogram
k, s_mt = sf.tapered_estimator(k, tapers=tapers, debiased=False)

# Plot
sf.plot_non_isotropic_estimator(k, s_mt, 
                                plot_type="radial", 
                                exact_sf=exact_sf, 
                                error_bar=True, bins=80,
                                scale="log",
                                rasterized=True, 
                                label=r"$\widehat{S}$")<jupyter_output><empty_output><jupyter_text>The asymptotic bias of $\widehat{S}_{\mathrm{MT}}$ at small wavenumber $\|k\|_2$ is visible. To deal with this bias we can use one of the following two debiased versions.<jupyter_code># Directly debiased multitapered estimator
from structure_factor.tapers import SineTaper
 
# Wavevectors
k_max = 8 # Threshold on the maximum wavenumber
x = np.linspace(-k_max, k_max, 16**2)
x = x[x != 0]
X, Y = np.meshgrid(x, x)
k = np.column_stack((X.ravel(), Y.ravel()))

# First 4 tapers of the family of sinusoidal tapers
from structure_factor.tapers import multi_sinetaper_grid
tapers = multi_sinetaper_grid(d=2, p_component_max=2)

# Scaled multitapered periodogram
k, s_ddmt = sf.tapered_estimator(k, tapers=tapers, debiased=True, direct=True)

# Plot
sf.plot_non_isotropic_estimator(k, s_ddmt, 
                                plot_type="all", 
                                exact_sf=exact_sf,  
                                error_bar=True, bins=80, 
                                scale="log", 
                                rasterized=True,
                                label=r"$\widehat{S}$")
# Undirectly debiased multitapered estimator
from structure_factor.tapers import SineTaper
 
# Wavevectors
k_max = 8 # Threshold on the maximum wavenumber
x = np.linspace(-k_max, k_max, 16**2)
x = x[x != 0]
X, Y = np.meshgrid(x, x)
k = np.column_stack((X.ravel(), Y.ravel()))

# First 4 tapers of the family of sinusoidal tapers
from structure_factor.tapers import multi_sinetaper_grid
tapers = multi_sinetaper_grid(d=2, p_component_max=2)

# Scaled multitapered periodogram
k, s_udmt = sf.tapered_estimator(k, tapers=tapers, debiased=True, direct=False)

# Plot
sf.plot_non_isotropic_estimator(k, s_ddmt, 
                                plot_type="imshow", 
                                exact_sf=exact_sf, 
                                error_bar=True, bins=80,
                                scale="log", 
                                rasterized=True, 
                                label=r"$\widehat{S}$")<jupyter_output><empty_output><jupyter_text>3.2- Estimators assuming stationarity and isotropy The estimators that assume the stationarity and isotropy of the point process, apply to a ``PointPattern`` having ``BallWindow``.As ``point_pattern_ball`` has a ``BallWindow`` we will be using it directly. In the other case, it's recommended to use a restriction.<jupyter_code>sf_isotropic = StructureFactor(point_pattern_ball)<jupyter_output><empty_output><jupyter_text>3.2.1- Bartlett's isotropic estimator Bartlett's isotropic estimator $\widehat{S}_{\mathrm{BI}}$ is an estimator of the structure factor $S$ of a stationary isotropic point process. It is a particular case of the isotropic tapered estimators using Bartlett's taper, in other words, it's the isotropic version of the scattering intensity. It can be evaluated on arbitrary wavenumbers or the allowed wavenumbers to reduce the bias.The complexity of this estimator is quadratic in the number of points of the ``PointPattern``.When dealing with a large number of points, it is recommended to start with a restricted version of the ``PointPattern``, before using the large sample and to increase the window radius respectively.<jupyter_code># Bartlett's isotropic estimator on arbitrary wavenumbers
# Running time = 156 s
import time
start_time = time.time()
k_norm = np.linspace(0.01, 7, 100)
k_norm, s_bi = sf_isotropic.bartlett_isotropic_estimator(k_norm=k_norm)
print("--- %s seconds ---" % (time.time() - start_time))

#Plot
fig, axis = plt.subplots(figsize=(7,6))
sf_isotropic.plot_isotropic_estimator(k_norm, s_bi, 
                                         axis=axis,
                                         exact_sf=exact_sf, 
                                         label=r"$\widehat{S}$")<jupyter_output><empty_output><jupyter_text>We can see the relevant bias for small wavenumbers<jupyter_code># Bartlett's isotropic estimator on allowed wavenumbers
# Running time = 156 s
import time

start_time = time.time()
k_norm_allowed, s_bi_k_norm_allowed = sf_isotropic.bartlett_isotropic_estimator(nb_values=60)
print("--- %s seconds ---" % (time.time() - start_time))

#Plot
fig, axis = plt.subplots(figsize=(7,6))
sf_isotropic.plot_isotropic_estimator(k_norm_allowed, s_bi_k_norm_allowed, 
                                         axis=axis,
                                         exact_sf=exact_sf, 
                                         label=r"$\widehat{S}$")<jupyter_output><empty_output><jupyter_text>This estimator seems to give the best results among all the estimators but, it's time-consuming.  3.2.2- Quadrature estimator isotropic **Warning**: This section relies on an interface between Python and R. Make sure that the R Programming language is available on your machine. For installation, see https://www.r-project.org/The last two isotropic estimators are based on, first estimating the pair correlation function $g$ of the ``PointPattern``,then interpolating/extrapolating the obtained results, and finally using Ogata/Baddour&Chouinard quadrature to estimate the Hankel transform of a function of g, corresponding to the structure factor. Let's start by estimating the pair correlation function.  3.2.2.1 - Pair correlation function **Warning**: This section requires the R program language https://www.rstudio.com/ to be available on your local machine. The toolbox contains two estimators of the pair correlation function (pcf) of a ``PointPattern``.These two methods are ``pcf.ppp`` and ``pcf.fv`` inherited from the R package ``spatstat`` https://spatstat.org/ . Approximating the pair correlation function using pcf.ppp<jupyter_code># pcf.ppp
import structure_factor.pair_correlation_function as pcf

r= np.linspace(0, 20, 200)
pcf_ppp = pcf.estimate(point_pattern_ball, # PointPattern
                        method="ppp", # Estimation method (could be "ppp" or "fv")
                        r=r, # Estimation radii 
                        correction="all" # Edge correction 
                              )

# Plot
pcf.plot(pcf_ppp, 
         exact_pcf=exact_pcf, 
         figsize=(7,6),
         color=['grey', 'b', 'darkcyan'], 
         style=[".", "*", "^"], 
        )<jupyter_output><empty_output><jupyter_text>Approximating the pair correlation function using pcf.fv<jupyter_code># pcf.fv
import structure_factor.pair_correlation_function as pcf

pcf_fv = pcf.estimate(point_pattern_ball, # PointPattern 
                      method="fv", # Estimation method (could be "ppp" or "fv")
                      Kest=dict(rmax=20), # Maximal estimation radius 
                      fv=dict(method="b", spar=0.2) # Correction method and sparsity
                             )

# Plot
pcf.plot(pcf_fv, 
         exact_pcf=exact_pcf, 
         figsize=(7,6), 
         color=['grey'], 
         style=["."]
        )<jupyter_output><empty_output><jupyter_text>After Approximating the pair correlation function the second step is to clean, interpolate, and extrapolate the result.We will be working with the approximation result of the method ``pcf.fv``.<jupyter_code>pcf_fv<jupyter_output><empty_output><jupyter_text>Interpolation<jupyter_code>r = pcf_fv["r"]
pcf_r = pcf_fv["pcf"]

# Interpolation
pcf_fct = pcf.interpolate(r=r, 
                          pcf_r=pcf_r, 
                          drop=True, # Drop outliers (nan, neginf, and posinf)
                          extrapolate_with_one=True # Extrapolate with 1 after max(r)
                                 )


# Plot
x = np.linspace(0, 100, 200)
plt.plot(x, pcf_fct(x), 'b.', label="Approximated pcf") 
plt.plot(x, exact_pcf(x), 'g', label="Exact pcf")
plt.legend()
plt.show()<jupyter_output><empty_output><jupyter_text>3.2.2.2- Estimate the structure factor using Ogata quadrature<jupyter_code># Ogata quadrature 
k_norm = np.linspace(0.5, 30, 1000) # Wavenumbers
k_norm, s_ho = sf_isotropic.quadrature_estimator_isotropic(pcf_fct, # Estimated pcf function
                                                 k_norm=k_norm, # wavenumbers
                                                 method="Ogata", # Quadrature method ("Ogata", or "BaddourChouinard")
                                                 step_size=0.01, # Step size
                                                 nb_points=1000 # Number of points
                                                )
# Plot
fig, axis = plt.subplots(figsize=(7,6))
fig = sf_isotropic.plot_isotropic_estimator(k_norm, s_ho, 
                                               axis=axis, 
                                               error_bar=True, bins=80, 
                                               exact_sf=exact_sf, 
                                               label=r"$\widehat{S}$",
                                               #file_name="ginibre_s_ho.pdf" 
                                              )<jupyter_output><empty_output><jupyter_text>3.2.2.2- Estimate the structure factor using Baddour & Chouinard quadrature<jupyter_code># Baddour & Chouinard quadrature 
k_norm = np.linspace(0.5, 30, 1000) # Wavenumbers
r_max = np.max(r) # Maximum radius for which the pcf has been approximated
k_norm, s_hbc = sf_isotropic.quadrature_estimator_isotropic(pcf_fct, # Estimated pcf function
                                                 k_norm=k_norm, # wavenumbers
                                                 method="BaddourChouinard", # Quadrature method ("Ogata", or "BaddourChouinard")
                                                 r_max=r_max, # Step size
                                                 nb_points=1000 # Number of points
                                                )
# Plot
fig, axis = plt.subplots(figsize=(7,6))
fig = sf_isotropic.plot_isotropic_estimator(k_norm, s_hbc, 
                                            axis=axis, 
                                            exact_sf=exact_sf, 
                                            label=r"$\widehat{S}$",
                                            #file_name="ginibre_s_hbc.pdf" 
                                              )<jupyter_output><empty_output><jupyter_text>3.4- Hyperuniformity Our strategy for studying the hyperuniformity of a point process is by, first studying the index $H$ of hyperuniformity of the ``PointPattern``.If $H< 10^{-3}$ then the point process is effectively hyperuniform and so maybe hyperuniform. In this case, we study the power decay to zero of the structure factor $\alpha$ which indicates the possible class of hyperuniformity.If the $H$ rejects the hypothesis of hyperuniformity then we conclude that the point process is not hyperuniform. In what follows, we will be using the results of Bartlett's isotropic estimator for studying the effective hyperuniformity and the hyperuniformity class of the Ginibre point pattern.We know that the Ginibre ensemble is a first-class hyperuniform point process with power decay $\alpha_{Ginibre} = 2$.<jupyter_code># Initialize ``Hyperuniformity``
from structure_factor.hyperuniformity import Hyperuniformity

hyperuniformity_test = Hyperuniformity(k_norm_allowed, s_bi_k_norm_allowed)<jupyter_output><empty_output><jupyter_text>1.3.1- Effective hyperuniformity<jupyter_code># Effective hyperuniformity
H_ginibre, _ = hyperuniformity_test.effective_hyperuniformity(k_norm_stop=0.2) # H index

# Visualization of the results
import matplotlib.pyplot as plt
import structure_factor.utils as utils
fitted_line = hyperuniformity_test.fitted_line # Fitted line to s_bi
x = np.linspace(0, 2, 300)
fig, axis =plt.subplots(figsize=(7,5))
axis.plot(k_norm_allowed, s_bi_k_norm_allowed, 'b', marker=".", label="Approximated structure factor")
axis.plot(x, fitted_line(x), 'r--', label= "Fitted line")
axis.plot(k_norm_allowed, GinibrePointProcess.structure_factor(k_norm_allowed), 'g', label=r"$S(k)$")
axis.annotate('H={}'.format(H_ginibre), xy=(0, 0), xytext=(0.01,0.3),
            arrowprops=dict(facecolor='black', shrink=0.01))
axis.legend()
axis.set_xlabel('wavelength (k)')
axis.set_ylabel(r"Structure factor ($\mathsf{S}(k)$")
plt.show()<jupyter_output><empty_output><jupyter_text>As $H<10^{-3}$, we conclude that the Ginibre ensemble is effectively hyperuniformity.  1.3.2- Hyperuniformity class<jupyter_code># Hyperuniformity class
alpha_ginibre, _ = hyperuniformity_test.hyperuniformity_class(k_norm_stop=0.4)

# Visualization of the results
import matplotlib.pyplot as plt
import structure_factor.utils as utils
fitted_poly = hyperuniformity_test.fitted_poly # Fitted polynomial to s_bi
fig, axis =plt.subplots(figsize=(7,5))
axis.plot(k_norm_allowed, s_bi_k_norm_allowed, 'b', marker=".", label="Approximated structure factor")
axis.plot(k_norm_allowed, GinibrePointProcess.structure_factor(k_norm_allowed), 'g', label=r"$S(k)$")
axis.plot(k_norm_allowed, fitted_poly(k_norm_allowed), 'r--', label= "Fitted line")
axis.annotate(r" $\alpha$ ={}".format(alpha_ginibre), xy=(0, 0), xytext=(0.01,0.4),
            arrowprops=dict(facecolor='black', shrink=0.1))
axis.legend()
axis.set_xlabel('wavelength (k)')
axis.set_ylabel(r"Structure factor ($\mathsf{S}(k)$")
plt.show()<jupyter_output><empty_output><jupyter_text>$\alpha \approx 1.99$ is a good approximation of the exact value $\alpha_{Ginibre}=2$.Thus this test successfully predicts the hyperuniformity class of the Ginibre Ensemble.<jupyter_code>print("--- %s seconds ---" % (time.time() - start_all))<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.0946688703539993, 'fraction_numerical': 0.01095437598493293, 'mean_word_length': 2.8132786164443795, 'pattern_counts': {'":': 0, '<': 103, '<?xml version=': 0, '>': 101, 'https://': 4, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 3, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 68, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '25', 'dir': 'jupyter-structured-clean-dedup', 'id': '125952', 'license': 'MIT', 'n_tokens_mistral': 8183, 'n_tokens_neox': 7558, 'n_words': 2146, 'path': 'notebooks/tutorial_structure_factor.ipynb', 'repo_name': 'For-a-few-DPPs-more/structure-factor', 'size': '26017'}