Skip to content

Commit adcae5d

Browse files
committed
v0.2.42 new lecture
* : * Note regarding reproducibility and non-reproducible RNGs. * Minor typo. * Updated Zenodo release. * , new switch , defaults to TRUE * new lecture and added to lecture's test.
1 parent c2fb1dc commit adcae5d

File tree

8 files changed

+273
-18
lines changed

8 files changed

+273
-18
lines changed

NEWS

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,12 @@
1+
v0.2.42
2+
3+
* `README.md`:
4+
* Note regarding reproducibility and non-reproducible RNGs.
5+
* Minor typo.
6+
* Updated Zenodo release.
7+
* `nnsd`, new switch `unfold`, defaults to TRUE
8+
* `spectral_unfolding.ipynb` new lecture and added to lecture's test.
9+
110
v0.2.38
211

312
* `runlectures.sh` is added for running lectures notebooks on CLI for testing.

README.md

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
[![Downloads](https://pepy.tech/badge/leymosun/month)](https://pepy.tech/project/leymosun)
66
[![Static Badge](https://img.shields.io/badge/HAL--Science-hal--03464130-blue)](https://hal.science/hal-03464130/)
77
![Static Badge](https://img.shields.io/badge/Produce--of-Cyprus-D57800)
8-
[![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.17578757.svg)](https://doi.org/10.5281/zenodo.17578757)
8+
[![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.17912257.svg)](https://doi.org/10.5281/zenodo.17912257)
99

1010

1111
A package for randomness based research.
@@ -29,6 +29,11 @@ specific release.
2929
The package provides tools and utilities for randomness based research with `High-Entropy Random Number Generation (HE-RNG)`. It means generation is performed with non-deterministic seeds every time a random
3030
library function is called.
3131

32+
Having non-reproducible and unpredictable RNGs could improve Monte Carlo and similar randomness
33+
based computational science experimentations. Non-reproducible RNGs can still generate reproducible
34+
research. Critical components in this direction is Uncertainty Quantification (UQ). Leymosun
35+
implements bootstrapped based UQ and confidence interval generations.
36+
3237
### High-entropy random number utilities
3338

3439
The core package is providing strong randomness improving the simulation quality. We use NumPy grammar and as a backend.
@@ -64,8 +69,8 @@ Lectures notes that introduce randomization concepts with the usage of `Leymosun
6469
* [wigner_semicircle.ipynb](https://github.com/msuzen/leymosun/blob/main/lectures/wigner_semicircle.ipynb): `Lecture on the Wigner's semicircle law`. The Wigner Semicircle law for the Gaussian Orthogonal Ensemble (GOE), comparison with the analytical case.
6570
* [wigner_dyson_spacing.ipynb](https://github.com/msuzen/leymosun/blob/main/lectures/wigner_dyson_spacing.ipynb): `Lecture on the Wigner-Dyson nearest-neighbour distribution`. The Wigner-Dyson spacing law for the Gaussian Orthogonal Ensemble (GOE), comparison with the analytical case.
6671
* [wigner_semicircle_mixed.ipynb](https://github.com/msuzen/leymosun/blob/main/lectures/wigner_semicircle_mixed.ipynb): `Lecture on the Wigner's cats`. Deviations from the Wigner Semicircle law for the mixed-Gaussian Orthogonal Ensemble (GOE). This would demonstrate, so-called "Wigner's Cats", i.e., the deviation makes the density looks like cat.
67-
* [he_rng_nist.ipynb](https://github.com/msuzen/leymosun/blob/main/lectures/he_rng_nist.ipynb): `Lecture on Understanding High-Entropy RNGs with NIST benchmark`. This lecture provides a way to test different RNGs or usage of RNGs via standard quality
68-
tests.
72+
* [spectral_unfolding.ipynb](https://github.com/msuzen/leymosun/blob/main/lectures/spectral_unfolding.ipynb): ` Self-consistent spectral unfolding` understanding what is a spectral unfolding.
73+
* [he_rng_nist.ipynb](https://github.com/msuzen/leymosun/blob/main/lectures/he_rng_nist.ipynb): `Lecture on Understanding High-Entropy RNGs with NIST benchmark`. This lecture provides a way to test different RNGs or usage of RNGs via standard quality tests.
6974

7075
## Development notes
7176
* Philosophy
@@ -100,7 +105,7 @@ We would be grateful for a citation of our paper(s) if you use `leymosun` or ide
100105

101106
## License
102107
[![License: GPL v3](https://img.shields.io/badge/License-GPLv3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0)
103-
[![License: CC BY 4.0](https://img.shields.io/badge/License-CC_BY_4.0-lightgrey.svg)](https://creativecommons.org/licenses/by/4.0/).
108+
[![License: CC BY 4.0](https://img.shields.io/badge/License-CC_BY_4.0-lightgrey.svg)](https://creativecommons.org/licenses/by/4.0/)
104109

105110
(c) 2025
106111
M. Süzen

assets/effect_unfolding.png

2.34 KB
Loading

lectures/spectral_unfolding.ipynb

Lines changed: 223 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,223 @@
1+
{
2+
"cells": [
3+
{
4+
"cell_type": "markdown",
5+
"id": "a5a75eb6",
6+
"metadata": {},
7+
"source": [
8+
"## Self-consistent spectral unfolding\n",
9+
"\n",
10+
" by M.Süzen\n",
11+
" (c) 2025\n",
12+
"\n",
13+
"Prerequisite to this tutorial is finishing the `wigner_semicircle.ipynb` and \n",
14+
"`wigner_dyson_spacing.ipynb` lectures first as a background. \n",
15+
"\n",
16+
"Spectral unfolding appears in quantum mechanical description of atomic systems \n",
17+
"from random matrix theory perspective. The core idea is to remove local fluctuations \n",
18+
"in the analysis of the spectra, and obtain a new `unfolded spectra`. \n",
19+
"\n",
20+
"In this lecture notes we will understand. \n",
21+
"\n",
22+
"* What does unfolding entails. \n",
23+
"* A robust way of doing this in detail. This is something \n",
24+
" called `self-consistent spectral unfolding`\n",
25+
"* How to just use `leymosun`'s tools to unfold a spectra: \n",
26+
" We will use `leymosun`"
27+
]
28+
},
29+
{
30+
"cell_type": "markdown",
31+
"id": "04206576",
32+
"metadata": {},
33+
"source": [
34+
"## Needed components \n",
35+
"\n",
36+
"Load all tools from `leymosun` that we would use"
37+
]
38+
},
39+
{
40+
"cell_type": "code",
41+
"execution_count": null,
42+
"id": "e37e3d19",
43+
"metadata": {},
44+
"outputs": [],
45+
"source": [
46+
"from leymosun.spectral import unfold_spectra, empirical_spectral_density, nnsd\n",
47+
"from leymosun.gaussian import goe \n",
48+
"import numpy as np\n",
49+
"import matplotlib.pyplot as plt\n",
50+
"import leymosun \n",
51+
"leymosun.__version__"
52+
]
53+
},
54+
{
55+
"cell_type": "markdown",
56+
"id": "e8edeb89",
57+
"metadata": {},
58+
"source": [
59+
"## Definition of spectral unfolding statistically \n",
60+
"\n",
61+
"The idea of unfolding is removing the fluctuations in spectra locally. \n",
62+
"Here, locally means in the vicinity of any given eigenvalues (singular values). \n",
63+
" This can be measured by nearest-neighbor spacing values $\\Delta e_{i}$, fluctuations. \n",
64+
" Then the mean fluctuation over $N$ sorted eigenvalues \n",
65+
" $\\Delta e_{i} = |e_{i}-e_{i-1}|$ should be close to $1.0$ \n",
66+
"\n",
67+
"If we `transformed` the empirical density $\\rho(e)$, via an `unfolding` procedure, \n",
68+
"that yields this mean value, $\\frac{1}{N} \\sum_{i=1}^{N} \\Delta e_{i} \\rightarrow 1.0$. \n",
69+
"It is important that it isn't smoothen as in smoothing the data, it is thought as of \n",
70+
"unfolding a rough paper or transformation or mapping, $P(x)$. $P(x)$ here is simply \n",
71+
"ranked of the sorted eigenvalues and similar to the concept of \n",
72+
"{\\it density of states} in the `unfolded` `raw` case.\n"
73+
]
74+
},
75+
{
76+
"cell_type": "markdown",
77+
"id": "53f23d7a",
78+
"metadata": {},
79+
"source": [
80+
"## Polynomial Unfolding: Self-consistent approach \n",
81+
"\n",
82+
"The approach starts with fitting a $n$ degree polynomial, \n",
83+
"$P(e) = \\sum_{k=0}^{k=n} a_{k} e^{k}$ to eigenvalues $e_{i}$. \n",
84+
"Then, we check which degree leads mean fluctuation of $1.0$. \n",
85+
"Essentially, we fit different degree polynomials on $(y, e_{i})$, \n",
86+
"where by $y$ is the rank order. This is what implemented in \n",
87+
"`leymosun`'s `unfold_spectra` functionality. "
88+
]
89+
},
90+
{
91+
"cell_type": "markdown",
92+
"id": "c89caa13",
93+
"metadata": {},
94+
"source": [
95+
"## Example: Raw and Unfolded spectrum\n",
96+
"\n",
97+
"In this example we will generate spectra from GOE and plot \n",
98+
"$(y, e_{i})$, where $e_{i}$. Let's just use ensemble of size 1. \n",
99+
"We choose a smaller matrix to see how unfolded eigenvalues looks \n",
100+
"close up as stair function. We compute eigenvalues and plot the \n",
101+
"sorted eigenvalues. "
102+
]
103+
},
104+
{
105+
"cell_type": "code",
106+
"execution_count": null,
107+
"id": "8bfdd8ba",
108+
"metadata": {},
109+
"outputs": [],
110+
"source": [
111+
"A = goe(50)\n",
112+
"eigenvalues, _, _ = empirical_spectral_density([A])\n",
113+
"eigenvalues = sorted(eigenvalues[0]) # as this was ensemble and raw sort them\n",
114+
"y= np.arange(1,len(eigenvalues))"
115+
]
116+
},
117+
{
118+
"cell_type": "code",
119+
"execution_count": null,
120+
"id": "ac75ed3c",
121+
"metadata": {},
122+
"outputs": [],
123+
"source": [
124+
"plt.stairs(y, eigenvalues)\n",
125+
"plt.title(\"Raw Spectra \")\n",
126+
"plt.xlabel(\"Eigenvalue Locations\")\n",
127+
"plt.ylabel(\"Density of States\")\n"
128+
]
129+
},
130+
{
131+
"cell_type": "markdown",
132+
"id": "0ecc958f",
133+
"metadata": {},
134+
"source": [
135+
"Let's compute the `mean fluctuations`, which must be far from 1.0. "
136+
]
137+
},
138+
{
139+
"cell_type": "code",
140+
"execution_count": null,
141+
"id": "feddb728",
142+
"metadata": {},
143+
"outputs": [],
144+
"source": [
145+
"np.mean(np.diff(eigenvalues))"
146+
]
147+
},
148+
{
149+
"cell_type": "markdown",
150+
"id": "f10187e9",
151+
"metadata": {},
152+
"source": [
153+
"Let's now unfold the spectrum with a polynomial self-consistent approach, \n",
154+
"here we use only up to a degree $10$ and do not remove outliers as this is a too small matrix \n",
155+
"for demonstration purposes. Then we see that `mean fluctuations` are close to $1.0$"
156+
]
157+
},
158+
{
159+
"cell_type": "code",
160+
"execution_count": null,
161+
"id": "9c777290",
162+
"metadata": {},
163+
"outputs": [],
164+
"source": [
165+
"unfolded_spec, _, _ = unfold_spectra(eigenvalues=eigenvalues, iqr=False, deg_max=20)\n",
166+
"np.mean(np.diff(unfolded_spec)) # ~1.0"
167+
]
168+
},
169+
{
170+
"cell_type": "markdown",
171+
"id": "b8630a13",
172+
"metadata": {},
173+
"source": [
174+
"Let's now compare local fluctuations over density of states."
175+
]
176+
},
177+
{
178+
"cell_type": "code",
179+
"execution_count": null,
180+
"id": "24d017c8",
181+
"metadata": {},
182+
"outputs": [],
183+
"source": [
184+
"plt.stairs(np.cumsum(np.diff(eigenvalues))/y, label= \"Raw spectrum\")\n",
185+
"plt.stairs(np.cumsum(np.diff(unfolded_spec))/y, label=\"Unfolded spectrum \")\n",
186+
"plt.title(\"Effect of Spectral Unfolding \")\n",
187+
"plt.ylabel(\"Eigenvalue Mean Fluctuations\")\n",
188+
"plt.xlabel(\"Density of States\")\n",
189+
"plt.xlim([1,49])\n",
190+
"plt.legend()"
191+
]
192+
},
193+
{
194+
"cell_type": "markdown",
195+
"id": "281cc145",
196+
"metadata": {},
197+
"source": [
198+
"**Exercise** Repeat the analysis for larger ensemble, $M=50$ and $N=500$. Plot with uncertainty quantification. Use `leymosun`'s `bootstrap_observed_matrix_ci` utility."
199+
]
200+
}
201+
],
202+
"metadata": {
203+
"kernelspec": {
204+
"display_name": "Python 3",
205+
"language": "python",
206+
"name": "python3"
207+
},
208+
"language_info": {
209+
"codemirror_mode": {
210+
"name": "ipython",
211+
"version": 3
212+
},
213+
"file_extension": ".py",
214+
"mimetype": "text/x-python",
215+
"name": "python",
216+
"nbconvert_exporter": "python",
217+
"pygments_lexer": "ipython3",
218+
"version": "3.11.6"
219+
}
220+
},
221+
"nbformat": 4,
222+
"nbformat_minor": 5
223+
}

leymosun/spectral.py

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ def empirical_spectral_density(
5959
mmes_order: If the ensemble is from mixed, put the max order used.
6060
Defaults to -1, not mixed order. When in use, this will
6161
pad the eigenvalues.
62-
MMES algorithm is based on Mixed Matrix Ensemble Sampling (MMES)
62+
MMES algorithm is based on Mixed Matrix Ensemble Sampling (MMES)
6363
Suzen 2021 https://hal.science/hal-03464130
6464
locations: Eigenvalue locations that we compute the density.
6565
defaults np.arange(-2.05, 2.1, 0.05). Note that
@@ -165,24 +165,30 @@ def unfold_spectra(eigenvalues: np.array, iqr: bool = True, deg_max: int = 32):
165165
return unfolded_eigen, np.diff(unfolded_eigen), deg_opt
166166

167167

168-
def nnsd(eigenvalues: np.array, locations: np.array = np.arange(0.0, 5.0, 0.1)):
169-
"""Compute Nearest-Neigbour Spacing Densities (NNSD) given eigenvalues with
168+
def nnsd(
169+
eigenvalues: np.array,
170+
locations: np.array = np.arange(0.0, 5.0, 0.1),
171+
unfold: bool = True,
172+
):
173+
"""Compute Nearest-Neigbour Spacing Densities (NNSD) given eigenvalues with
170174
polynomial unfolding.
171175
172176
Args:
173177
eigenvalues: 2D, eigenvalues over repeaded samples.
174-
locations: Centers to compute PDF of NNSD.
178+
locations: Centers to compute PDF of NNSD, defaults to [0, 5] with 0.1 spacing.
179+
unfold: whether to unfold, defaults to True.
175180
176181
Returns:
177-
Tuple of two: NNSDs 2D and location bins
182+
Tuple of three: NNSDs 2D and location bins
178183
179184
"""
180185
nnsd_densities = []
181186
for eigenvalue in eigenvalues:
182-
_, ueigenvalues_nn, _ = unfold_spectra(
183-
eigenvalue, deg_max=30, iqr=True
184-
)
185-
density, _locations = pdf(ueigenvalues_nn, locations=locations)
187+
if unfold:
188+
_, eigenvalue, _ = unfold_spectra(eigenvalue, deg_max=30, iqr=True)
189+
else:
190+
eigenvalue = np.diff(eigenvalue)
191+
density, _locations = pdf(eigenvalue, locations=locations)
186192
nnsd_densities.append(density)
187193
return np.array(nnsd_densities), np.array(_locations)
188194

@@ -201,11 +207,13 @@ def mean_adjacent_gap_ratio(eigenvalues):
201207
"""
202208
adjacent_gap_ratios = []
203209
adjacent_gap_ratios_mean = []
204-
for eigens in eigenvalues:
210+
for eigens in eigenvalues:
205211
eigens_sorted = np.sort(eigens)
206212
spacings = np.diff(eigens_sorted)
207-
adjacent_gap_ratio = np.minimum(spacings[:-1], spacings[1:]) /(np.maximum(spacings[:-1], spacings[1:])+1e-9)
213+
adjacent_gap_ratio = np.minimum(spacings[:-1], spacings[1:]) / (
214+
np.maximum(spacings[:-1], spacings[1:]) + 1e-9
215+
)
208216
adjacent_gap_ratios.append(adjacent_gap_ratio)
209217
adjacent_gap_ratios_mean.append(np.mean(adjacent_gap_ratio))
210218
bar_adjacent_gap_ratio = np.mean(adjacent_gap_ratios_mean)
211-
return bar_adjacent_gap_ratio, adjacent_gap_ratios
219+
return bar_adjacent_gap_ratio, adjacent_gap_ratios

leymosun/stats.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44

55
def pdf(values: np.array, locations: np.array) -> tuple[np.array, np.array]:
6-
"""Compute density given values and arbitary monotonic locations of bin centres.
6+
"""Compute density given values and arbitrary monotonic locations of bin centres.
77
88
Args:
99
values: set of values that density should be computed.

leymosun/version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
__version__="0.2.38"
1+
__version__="0.2.42"

runlectures.sh

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,3 +43,13 @@ python lecturePy/wigner_semicircle.py
4343
echo " "
4444
echo " Success running wigner_semicircle.ipynb"
4545
echo " "
46+
# spectral_unfolding.ipynb
47+
echo " "
48+
echo " Running spectral_unfolding.ipynb"
49+
echo " "
50+
rm -f lecturePy/wigner_semicircle.py
51+
jupyter nbconvert --to python lectures/spectral_unfolding.ipynb --output-dir=./lecturePy --log-level=ERROR
52+
python lecturePy/spectral_unfolding.py
53+
echo " "
54+
echo " Success running spectral_unfolding.ipynb"
55+
echo " "

0 commit comments

Comments
 (0)