Spaces:
Running
Running
Update app.py
Browse files
app.py
CHANGED
@@ -3,6 +3,7 @@ import sympy as sp
|
|
3 |
import numpy as np
|
4 |
import plotly.graph_objects as go
|
5 |
from scipy.optimize import fsolve
|
|
|
6 |
|
7 |
# Configure Streamlit for Hugging Face Spaces
|
8 |
st.set_page_config(
|
@@ -336,62 +337,70 @@ def generate_root_plots(beta, y, z_a, z_min, z_max, n_points):
|
|
336 |
xaxis_title="z", yaxis_title="Re{s}", hovermode="x unified")
|
337 |
return fig_im, fig_re
|
338 |
|
339 |
-
# New function for
|
340 |
@st.cache_data
|
341 |
-
def
|
342 |
"""
|
343 |
-
Compute the eigenvalue distribution
|
344 |
|
345 |
-
|
346 |
-
|
347 |
-
|
348 |
-
|
349 |
-
|
350 |
-
|
351 |
|
352 |
-
|
|
|
|
|
|
|
|
|
353 |
|
354 |
-
for
|
355 |
-
|
356 |
-
|
357 |
-
|
358 |
-
def fixed_point_equation(m_real_imag):
|
359 |
-
m_real, m_imag = m_real_imag
|
360 |
-
m = complex(m_real, m_imag)
|
361 |
-
|
362 |
-
term1 = beta / (z_a - z - y * m * second_moment)
|
363 |
-
term2 = (1-beta) / (1 - z - y * m * second_moment)
|
364 |
-
|
365 |
-
result = term1 + term2 - m
|
366 |
-
|
367 |
-
return [result.real, result.imag]
|
368 |
|
369 |
-
#
|
370 |
-
|
371 |
-
|
372 |
-
|
373 |
|
374 |
-
# Compute
|
375 |
-
|
|
|
376 |
|
377 |
-
|
378 |
-
density_values = np.maximum(density_values, 0)
|
379 |
-
|
380 |
-
return x_values, density_values
|
381 |
|
382 |
-
def
|
383 |
"""
|
384 |
-
Generate a plot of the eigenvalue distribution.
|
385 |
"""
|
386 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
387 |
|
|
|
388 |
fig = go.Figure()
|
389 |
fig.add_trace(go.Scatter(x=x_values, y=density_values, mode="lines",
|
390 |
name="Eigenvalue Density", line=dict(color='blue', width=2)))
|
391 |
|
|
|
|
|
|
|
|
|
|
|
392 |
fig.update_layout(
|
393 |
-
title=f"Eigenvalue Distribution (β={beta:.3f}, y={y:.3f}, z_a={z_a:.3f})",
|
394 |
-
xaxis_title="
|
395 |
yaxis_title="Density",
|
396 |
hovermode="x unified"
|
397 |
)
|
@@ -470,9 +479,9 @@ with tab2:
|
|
470 |
|
471 |
# Add new settings for eigenvalue distribution
|
472 |
st.subheader("Eigenvalue Distribution Settings")
|
473 |
-
|
474 |
-
|
475 |
-
|
476 |
|
477 |
if st.button("Compute", key="tab2_button"):
|
478 |
with col2:
|
@@ -481,18 +490,24 @@ with tab2:
|
|
481 |
st.plotly_chart(fig_im, use_container_width=True)
|
482 |
st.plotly_chart(fig_re, use_container_width=True)
|
483 |
|
484 |
-
# Add eigenvalue distribution plot
|
485 |
-
|
486 |
-
|
|
|
487 |
|
488 |
st.markdown("""
|
489 |
### Eigenvalue Distribution Explanation
|
490 |
-
This plot shows the
|
491 |
-
- X is a p×n matrix with p/n
|
492 |
- Elements of X are i.i.d. following distribution β·δ_a + (1-β)·δ_1
|
493 |
- a = z_a, y = y, β = β
|
494 |
|
495 |
-
The distribution is
|
|
|
|
|
|
|
|
|
|
|
496 |
""")
|
497 |
|
498 |
# ----- Tab 3: Differential Analysis -----
|
|
|
3 |
import numpy as np
|
4 |
import plotly.graph_objects as go
|
5 |
from scipy.optimize import fsolve
|
6 |
+
from scipy.stats import gaussian_kde
|
7 |
|
8 |
# Configure Streamlit for Hugging Face Spaces
|
9 |
st.set_page_config(
|
|
|
337 |
xaxis_title="z", yaxis_title="Re{s}", hovermode="x unified")
|
338 |
return fig_im, fig_re
|
339 |
|
340 |
+
# New function for computing eigenvalue distribution directly
|
341 |
@st.cache_data
|
342 |
+
def compute_eigenvalue_distribution_direct(z_a, y, beta, n, num_samples=10):
|
343 |
"""
|
344 |
+
Compute the eigenvalue distribution by directly generating random matrices and computing eigenvalues.
|
345 |
|
346 |
+
Parameters:
|
347 |
+
- z_a: The value 'a' in the distribution β·δ_a + (1-β)·δ_1
|
348 |
+
- y: The asymptotic ratio p/n
|
349 |
+
- beta: The mixing coefficient in the distribution
|
350 |
+
- n: Size of the matrix dimension n
|
351 |
+
- num_samples: Number of random matrices to generate for averaging
|
352 |
|
353 |
+
Returns:
|
354 |
+
- all_eigenvalues: Array of all eigenvalues from all samples
|
355 |
+
"""
|
356 |
+
p = int(y * n) # Calculate p based on aspect ratio y
|
357 |
+
all_eigenvalues = []
|
358 |
|
359 |
+
for _ in range(num_samples):
|
360 |
+
# Generate random matrix X with elements following β·δ_a + (1-β)·δ_1
|
361 |
+
# This means each element is 'a' with probability β, and 1 with probability (1-β)
|
362 |
+
random_values = np.random.choice([z_a, 1.0], size=(p, n), p=[beta, 1-beta])
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
363 |
|
364 |
+
# Compute B_n = (1/n)XX*
|
365 |
+
X = random_values
|
366 |
+
XX_star = X @ X.T
|
367 |
+
B_n = XX_star / n
|
368 |
|
369 |
+
# Compute eigenvalues
|
370 |
+
eigenvalues = np.linalg.eigvalsh(B_n)
|
371 |
+
all_eigenvalues.extend(eigenvalues)
|
372 |
|
373 |
+
return np.array(all_eigenvalues)
|
|
|
|
|
|
|
374 |
|
375 |
+
def generate_esd_plot_direct(z_a, y, beta, n, num_samples=10, bandwidth=0.1):
|
376 |
"""
|
377 |
+
Generate a plot of the eigenvalue distribution using KDE.
|
378 |
"""
|
379 |
+
# Compute eigenvalues
|
380 |
+
eigenvalues = compute_eigenvalue_distribution_direct(z_a, y, beta, n, num_samples)
|
381 |
+
|
382 |
+
# Use KDE to estimate the density
|
383 |
+
kde = gaussian_kde(eigenvalues, bw_method=bandwidth)
|
384 |
+
|
385 |
+
# Generate points for plotting
|
386 |
+
x_min = max(0, np.min(eigenvalues) - 0.5)
|
387 |
+
x_max = np.max(eigenvalues) + 0.5
|
388 |
+
x_values = np.linspace(x_min, x_max, 1000)
|
389 |
+
density_values = kde(x_values)
|
390 |
|
391 |
+
# Create the plot
|
392 |
fig = go.Figure()
|
393 |
fig.add_trace(go.Scatter(x=x_values, y=density_values, mode="lines",
|
394 |
name="Eigenvalue Density", line=dict(color='blue', width=2)))
|
395 |
|
396 |
+
# Add individual eigenvalue points as a rug plot
|
397 |
+
fig.add_trace(go.Scatter(x=eigenvalues, y=np.zeros_like(eigenvalues),
|
398 |
+
mode="markers", name="Eigenvalues",
|
399 |
+
marker=dict(color='red', size=3, opacity=0.5)))
|
400 |
+
|
401 |
fig.update_layout(
|
402 |
+
title=f"Eigenvalue Distribution (β={beta:.3f}, y={y:.3f}, z_a={z_a:.3f}, n={n})",
|
403 |
+
xaxis_title="Eigenvalue",
|
404 |
yaxis_title="Density",
|
405 |
hovermode="x unified"
|
406 |
)
|
|
|
479 |
|
480 |
# Add new settings for eigenvalue distribution
|
481 |
st.subheader("Eigenvalue Distribution Settings")
|
482 |
+
matrix_size = st.slider("Matrix size (n)", min_value=50, max_value=1000, value=200, step=50, key="matrix_size")
|
483 |
+
num_samples = st.slider("Number of matrix samples", min_value=1, max_value=50, value=10, step=1, key="num_samples")
|
484 |
+
bandwidth = st.slider("KDE bandwidth", min_value=0.01, max_value=0.5, value=0.1, step=0.01, key="kde_bandwidth")
|
485 |
|
486 |
if st.button("Compute", key="tab2_button"):
|
487 |
with col2:
|
|
|
490 |
st.plotly_chart(fig_im, use_container_width=True)
|
491 |
st.plotly_chart(fig_re, use_container_width=True)
|
492 |
|
493 |
+
# Add eigenvalue distribution plot with direct computation and KDE
|
494 |
+
with st.spinner("Computing eigenvalue distribution..."):
|
495 |
+
fig_esd = generate_esd_plot_direct(z_a_2, y_2, beta, matrix_size, num_samples, bandwidth)
|
496 |
+
st.plotly_chart(fig_esd, use_container_width=True)
|
497 |
|
498 |
st.markdown("""
|
499 |
### Eigenvalue Distribution Explanation
|
500 |
+
This plot shows the eigenvalue distribution of B_n = (1/n)XX* where:
|
501 |
+
- X is a p×n matrix with p/n = y
|
502 |
- Elements of X are i.i.d. following distribution β·δ_a + (1-β)·δ_1
|
503 |
- a = z_a, y = y, β = β
|
504 |
|
505 |
+
The distribution is computed by:
|
506 |
+
1. Directly generating random matrices with the specified distribution
|
507 |
+
2. Computing the eigenvalues of B_n
|
508 |
+
3. Using Kernel Density Estimation (KDE) to visualize the distribution
|
509 |
+
|
510 |
+
Red markers at the bottom indicate individual eigenvalues.
|
511 |
""")
|
512 |
|
513 |
# ----- Tab 3: Differential Analysis -----
|