euler314 commited on
Commit
0357330
·
verified ·
1 Parent(s): 319d05d

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +78 -107
app.py CHANGED
@@ -90,21 +90,7 @@ def sweep_beta_and_find_z_bounds(z_a, y, z_min, z_max, beta_steps, z_steps):
90
  z_max_values.append(np.max(roots))
91
  return betas, np.array(z_min_values), np.array(z_max_values)
92
 
93
- @st.cache_data
94
- def compute_low_y_curve(betas, z_a, y):
95
- """
96
- Compute the "Low y Expression" curve.
97
- """
98
- betas = np.array(betas)
99
- with np.errstate(invalid='ignore', divide='ignore'):
100
- sqrt_term = y * betas * (z_a - 1)
101
- sqrt_term = np.where(sqrt_term < 0, np.nan, np.sqrt(sqrt_term))
102
- term = (-1 + sqrt_term) / z_a
103
- numerator = (y - 2)*term + y * betas * ((z_a - 1)/z_a) - 1/z_a - 1
104
- denominator = term**2 + term
105
- mask = (denominator != 0) & ~np.isnan(denominator) & ~np.isnan(numerator)
106
- result = np.where(mask, numerator/denominator, np.nan)
107
- return result
108
 
109
  @st.cache_data
110
  def compute_high_y_curve(betas, z_a, y):
@@ -144,7 +130,7 @@ def compute_all_derivatives(betas, z_mins, z_maxs, low_y_curve, high_y_curve, al
144
  # Lower z*(β)
145
  derivatives['lower'] = compute_derivatives(z_mins, betas)
146
 
147
- # Low y Expression
148
  if low_y_curve is not None:
149
  derivatives['low_y'] = compute_derivatives(low_y_curve, betas)
150
 
@@ -212,10 +198,7 @@ def generate_z_vs_beta_plot(z_a, y, z_min, z_max, beta_steps, z_steps,
212
 
213
  betas = np.linspace(0, 1, beta_steps)
214
  betas, z_mins, z_maxs = sweep_beta_and_find_z_bounds(z_a, y, z_min, z_max, beta_steps, z_steps)
215
-
216
- # Remove low_y_curve computation and display as requested
217
- # low_y_curve = compute_low_y_curve(betas, z_a, y) # Commented out
218
-
219
  high_y_curve = compute_high_y_curve(betas, z_a, y)
220
  alt_low_expr = compute_alternate_low_expr(betas, z_a, y)
221
 
@@ -239,11 +222,7 @@ def generate_z_vs_beta_plot(z_a, y, z_min, z_max, beta_steps, z_steps,
239
  name="Upper z*(β)", line=dict(color='blue')))
240
  fig.add_trace(go.Scatter(x=betas, y=z_mins, mode="markers+lines",
241
  name="Lower z*(β)", line=dict(color='lightblue')))
242
-
243
- # Remove low_y_curve trace as requested
244
- # fig.add_trace(go.Scatter(x=betas, y=low_y_curve, mode="markers+lines",
245
- # name="Low y Expression", line=dict(color='red')))
246
-
247
  fig.add_trace(go.Scatter(x=betas, y=high_y_curve, mode="markers+lines",
248
  name="High y Expression", line=dict(color='green')))
249
  fig.add_trace(go.Scatter(x=betas, y=alt_low_expr, mode="markers+lines",
@@ -261,7 +240,7 @@ def generate_z_vs_beta_plot(z_a, y, z_min, z_max, beta_steps, z_steps,
261
  curve_info = [
262
  ('upper', 'Upper z*(β)', 'blue'),
263
  ('lower', 'Lower z*(β)', 'lightblue'),
264
- # ('low_y', 'Low y', 'red'), # Removed as requested
265
  ('high_y', 'High y', 'green'),
266
  ('alt_low', 'Alt Low', 'orange')
267
  ]
@@ -337,72 +316,68 @@ def generate_root_plots(beta, y, z_a, z_min, z_max, n_points):
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
  )
407
 
408
  return fig
@@ -410,7 +385,7 @@ def generate_esd_plot_direct(z_a, y, beta, n, num_samples=10, bandwidth=0.1):
410
  # ----------------- Streamlit UI -----------------
411
  st.title("Cubic Root Analysis")
412
 
413
- # Define three tabs (removed "Curve Intersections" tab)
414
  tab1, tab2, tab3 = st.tabs(["z*(β) Curves", "Im{s} vs. z", "Differential Analysis"])
415
 
416
  # ----- Tab 1: z*(β) Curves -----
@@ -464,9 +439,9 @@ with tab1:
464
  - Dotted lines: Second derivatives (d²/dβ²)
465
  """)
466
 
467
- # ----- Tab 2: Im{s} vs. z and Eigenvalue Distribution -----
468
  with tab2:
469
- st.header("Plot Complex Roots vs. z and Eigenvalue Distribution")
470
  col1, col2 = st.columns([1, 2])
471
  with col1:
472
  beta = st.number_input("β", value=0.5, min_value=0.0, max_value=1.0, key="beta_tab2")
@@ -476,39 +451,35 @@ with tab2:
476
  z_max_2 = st.number_input("z_max", value=10.0, key="z_max_tab2")
477
  with st.expander("Resolution Settings"):
478
  z_points = st.slider("z grid points", min_value=1000, max_value=10000, value=5000, step=500, key="z_points")
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:
488
  fig_im, fig_re = generate_root_plots(beta, y_2, z_a_2, z_min_2, z_max_2, z_points)
489
  if fig_im is not None and fig_re is not None:
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 -----
514
  with tab3:
 
90
  z_max_values.append(np.max(roots))
91
  return betas, np.array(z_min_values), np.array(z_max_values)
92
 
93
+ # Removed the compute_low_y_curve function
 
 
 
 
 
 
 
 
 
 
 
 
 
 
94
 
95
  @st.cache_data
96
  def compute_high_y_curve(betas, z_a, y):
 
130
  # Lower z*(β)
131
  derivatives['lower'] = compute_derivatives(z_mins, betas)
132
 
133
+ # Low y Expression (only if provided)
134
  if low_y_curve is not None:
135
  derivatives['low_y'] = compute_derivatives(low_y_curve, betas)
136
 
 
198
 
199
  betas = np.linspace(0, 1, beta_steps)
200
  betas, z_mins, z_maxs = sweep_beta_and_find_z_bounds(z_a, y, z_min, z_max, beta_steps, z_steps)
201
+ # Removed low_y_curve computation
 
 
 
202
  high_y_curve = compute_high_y_curve(betas, z_a, y)
203
  alt_low_expr = compute_alternate_low_expr(betas, z_a, y)
204
 
 
222
  name="Upper z*(β)", line=dict(color='blue')))
223
  fig.add_trace(go.Scatter(x=betas, y=z_mins, mode="markers+lines",
224
  name="Lower z*(β)", line=dict(color='lightblue')))
225
+ # Removed the Low y Expression trace
 
 
 
 
226
  fig.add_trace(go.Scatter(x=betas, y=high_y_curve, mode="markers+lines",
227
  name="High y Expression", line=dict(color='green')))
228
  fig.add_trace(go.Scatter(x=betas, y=alt_low_expr, mode="markers+lines",
 
240
  curve_info = [
241
  ('upper', 'Upper z*(β)', 'blue'),
242
  ('lower', 'Lower z*(β)', 'lightblue'),
243
+ # Removed low_y curve
244
  ('high_y', 'High y', 'green'),
245
  ('alt_low', 'Alt Low', 'orange')
246
  ]
 
316
  xaxis_title="z", yaxis_title="Re{s}", hovermode="x unified")
317
  return fig_im, fig_re
318
 
 
319
  @st.cache_data
320
+ def generate_eigenvalue_distribution(beta, y, z_a, n=1000, seed=42):
321
  """
322
+ Generate the eigenvalue distribution of B_n = S_n T_n as n→∞
323
 
324
  Parameters:
325
+ -----------
326
+ beta : float
327
+ Fraction of components equal to z_a
328
+ y : float
329
+ Aspect ratio p/n
330
+ z_a : float
331
+ Value for the delta mass at z_a
332
+ n : int
333
+ Number of samples
334
+ seed : int
335
+ Random seed for reproducibility
336
  """
337
+ # Set random seed
338
+ np.random.seed(seed)
339
 
340
+ # Compute dimension p based on aspect ratio y
341
+ p = int(y * n)
 
 
 
 
 
 
 
 
 
 
 
342
 
343
+ # Constructing T_n (Population / Shape Matrix)
344
+ T_diag = np.where(np.random.rand(p) < beta, z_a, 1.0)
345
+ T_n = np.diag(T_diag)
 
 
 
 
 
346
 
347
+ # Generate the data matrix X with i.i.d. standard normal entries
348
+ X = np.random.randn(p, n)
349
 
350
+ # Compute the sample covariance matrix S_n = (1/n) * XX^T
351
+ S_n = (1 / n) * (X @ X.T)
 
 
 
352
 
353
+ # Compute B_n = S_n T_n
354
+ B_n = S_n @ T_n
355
+
356
+ # Compute eigenvalues of B_n
357
+ eigenvalues = np.linalg.eigvalsh(B_n)
358
+
359
+ # Use KDE to compute a smooth density estimate
360
+ kde = gaussian_kde(eigenvalues)
361
+ x_vals = np.linspace(min(eigenvalues), max(eigenvalues), 500)
362
+ kde_vals = kde(x_vals)
363
+
364
+ # Create figure
365
  fig = go.Figure()
 
 
366
 
367
+ # Add histogram trace
368
+ fig.add_trace(go.Histogram(x=eigenvalues, histnorm='probability density',
369
+ name="Histogram", marker=dict(color='blue', opacity=0.6)))
370
+
371
+ # Add KDE trace
372
+ fig.add_trace(go.Scatter(x=x_vals, y=kde_vals, mode="lines",
373
+ name="KDE", line=dict(color='red', width=2)))
374
 
375
  fig.update_layout(
376
+ title=f"Eigenvalue Distribution for B_n = S_n T_n (y={y:.1f}, β={beta:.2f}, a={z_a:.1f})",
377
  xaxis_title="Eigenvalue",
378
  yaxis_title="Density",
379
+ hovermode="closest",
380
+ showlegend=True
381
  )
382
 
383
  return fig
 
385
  # ----------------- Streamlit UI -----------------
386
  st.title("Cubic Root Analysis")
387
 
388
+ # Define three tabs (removed "Curve Intersections")
389
  tab1, tab2, tab3 = st.tabs(["z*(β) Curves", "Im{s} vs. z", "Differential Analysis"])
390
 
391
  # ----- Tab 1: z*(β) Curves -----
 
439
  - Dotted lines: Second derivatives (d²/dβ²)
440
  """)
441
 
442
+ # ----- Tab 2: Im{s} vs. z -----
443
  with tab2:
444
+ st.header("Plot Complex Roots vs. z")
445
  col1, col2 = st.columns([1, 2])
446
  with col1:
447
  beta = st.number_input("β", value=0.5, min_value=0.0, max_value=1.0, key="beta_tab2")
 
451
  z_max_2 = st.number_input("z_max", value=10.0, key="z_max_tab2")
452
  with st.expander("Resolution Settings"):
453
  z_points = st.slider("z grid points", min_value=1000, max_value=10000, value=5000, step=500, key="z_points")
454
+ if st.button("Compute Complex Roots vs. z", key="tab2_button"):
 
 
 
 
 
 
 
455
  with col2:
456
  fig_im, fig_re = generate_root_plots(beta, y_2, z_a_2, z_min_2, z_max_2, z_points)
457
  if fig_im is not None and fig_re is not None:
458
  st.plotly_chart(fig_im, use_container_width=True)
459
  st.plotly_chart(fig_re, use_container_width=True)
460
+
461
+ # Add a separator
462
+ st.markdown("---")
463
+
464
+ # Add eigenvalue distribution section
465
+ st.header("Eigenvalue Distribution for B_n = S_n T_n")
466
+ st.markdown("""
467
+ This simulation generates the eigenvalue distribution of B_n as n→∞, where:
468
+ - B_n = (1/n)XX* with X being a p×n matrix
469
+ - p/n y as n→∞
470
+ - All elements of X are i.i.d with distribution β·δ(z_a) + (1-β)·δ(1)
471
+ """)
472
+
473
+ col_eigen1, col_eigen2 = st.columns([1, 2])
474
+ with col_eigen1:
475
+ n_samples = st.slider("Number of samples (n)", min_value=100, max_value=2000, value=1000, step=100)
476
+ sim_seed = st.number_input("Random seed", min_value=1, max_value=1000, value=42, step=1)
477
+
478
+ if st.button("Generate Eigenvalue Distribution", key="tab2_eigen_button"):
479
+ with col_eigen2:
480
+ fig_eigen = generate_eigenvalue_distribution(beta, y_2, z_a_2, n=n_samples, seed=sim_seed)
481
+ if fig_eigen is not None:
482
+ st.plotly_chart(fig_eigen, use_container_width=True)
483
 
484
  # ----- Tab 3: Differential Analysis -----
485
  with tab3: