euler314 commited on
Commit
7a1ddff
·
verified ·
1 Parent(s): c02def7

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +104 -25
app.py CHANGED
@@ -88,6 +88,7 @@ def sweep_beta_and_find_z_bounds(z_a, y, z_min, z_max, beta_steps, z_steps):
88
  z_min_values.append(np.min(roots))
89
  z_max_values.append(np.max(roots))
90
  return betas, np.array(z_min_values), np.array(z_max_values)
 
91
  @st.cache_data
92
  def compute_low_y_curve(betas, z_a, y):
93
  """
@@ -143,7 +144,8 @@ def compute_all_derivatives(betas, z_mins, z_maxs, low_y_curve, high_y_curve, al
143
  derivatives['lower'] = compute_derivatives(z_mins, betas)
144
 
145
  # Low y Expression
146
- derivatives['low_y'] = compute_derivatives(low_y_curve, betas)
 
147
 
148
  # High y Expression
149
  derivatives['high_y'] = compute_derivatives(high_y_curve, betas)
@@ -198,6 +200,7 @@ def compute_custom_expression(betas, z_a, y, s_num_expr, s_denom_expr, is_s_base
198
  if np.isscalar(result):
199
  result = np.full_like(betas, result)
200
  return result
 
201
  def generate_z_vs_beta_plot(z_a, y, z_min, z_max, beta_steps, z_steps,
202
  s_num_expr=None, s_denom_expr=None,
203
  z_num_expr=None, z_denom_expr=None,
@@ -208,7 +211,10 @@ def generate_z_vs_beta_plot(z_a, y, z_min, z_max, beta_steps, z_steps,
208
 
209
  betas = np.linspace(0, 1, beta_steps)
210
  betas, z_mins, z_maxs = sweep_beta_and_find_z_bounds(z_a, y, z_min, z_max, beta_steps, z_steps)
211
- low_y_curve = compute_low_y_curve(betas, z_a, y)
 
 
 
212
  high_y_curve = compute_high_y_curve(betas, z_a, y)
213
  alt_low_expr = compute_alternate_low_expr(betas, z_a, y)
214
 
@@ -222,7 +228,7 @@ def generate_z_vs_beta_plot(z_a, y, z_min, z_max, beta_steps, z_steps,
222
 
223
  # Compute derivatives if needed
224
  if show_derivatives:
225
- derivatives = compute_all_derivatives(betas, z_mins, z_maxs, low_y_curve, high_y_curve,
226
  alt_low_expr, custom_curve1, custom_curve2)
227
 
228
  fig = go.Figure()
@@ -232,8 +238,11 @@ def generate_z_vs_beta_plot(z_a, y, z_min, z_max, beta_steps, z_steps,
232
  name="Upper z*(β)", line=dict(color='blue')))
233
  fig.add_trace(go.Scatter(x=betas, y=z_mins, mode="markers+lines",
234
  name="Lower z*(β)", line=dict(color='lightblue')))
235
- fig.add_trace(go.Scatter(x=betas, y=low_y_curve, mode="markers+lines",
236
- name="Low y Expression", line=dict(color='red')))
 
 
 
237
  fig.add_trace(go.Scatter(x=betas, y=high_y_curve, mode="markers+lines",
238
  name="High y Expression", line=dict(color='green')))
239
  fig.add_trace(go.Scatter(x=betas, y=alt_low_expr, mode="markers+lines",
@@ -251,7 +260,7 @@ def generate_z_vs_beta_plot(z_a, y, z_min, z_max, beta_steps, z_steps,
251
  curve_info = [
252
  ('upper', 'Upper z*(β)', 'blue'),
253
  ('lower', 'Lower z*(β)', 'lightblue'),
254
- ('low_y', 'Low y', 'red'),
255
  ('high_y', 'High y', 'green'),
256
  ('alt_low', 'Alt Low', 'orange')
257
  ]
@@ -281,6 +290,7 @@ def generate_z_vs_beta_plot(z_a, y, z_min, z_max, beta_steps, z_steps,
281
  )
282
  )
283
  return fig
 
284
  def compute_cubic_roots(z, beta, z_a, y):
285
  """
286
  Compute the roots of the cubic equation for given parameters.
@@ -326,11 +336,73 @@ def generate_root_plots(beta, y, z_a, z_min, z_max, n_points):
326
  xaxis_title="z", yaxis_title="Re{s}", hovermode="x unified")
327
  return fig_im, fig_re
328
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
329
  # ----------------- Streamlit UI -----------------
330
  st.title("Cubic Root Analysis")
331
 
332
- # Define four tabs
333
- tab1, tab2, tab3, tab4 = st.tabs(["z*(β) Curves", "Im{s} vs. z", "Curve Intersections", "Differential Analysis"])
334
 
335
  # ----- Tab 1: z*(β) Curves -----
336
  with tab1:
@@ -371,7 +443,6 @@ with tab1:
371
  st.markdown("""
372
  - **Upper z*(β)** (Blue): Maximum z value where discriminant is zero
373
  - **Lower z*(β)** (Light Blue): Minimum z value where discriminant is zero
374
- - **Low y Expression** (Red): Asymptotic approximation for low y values
375
  - **High y Expression** (Green): Asymptotic approximation for high y values
376
  - **Alternate Low Expression** (Orange): Alternative asymptotic expression
377
  - **Custom Expression 1** (Purple): Result from user-defined s substituted into the main formula
@@ -384,9 +455,9 @@ with tab1:
384
  - Dotted lines: Second derivatives (d²/dβ²)
385
  """)
386
 
387
- # ----- Tab 2: Im{s} vs. z -----
388
  with tab2:
389
- st.header("Plot Complex Roots vs. z")
390
  col1, col2 = st.columns([1, 2])
391
  with col1:
392
  beta = st.number_input("β", value=0.5, min_value=0.0, max_value=1.0, key="beta_tab2")
@@ -396,12 +467,33 @@ with tab2:
396
  z_max_2 = st.number_input("z_max", value=10.0, key="z_max_tab2")
397
  with st.expander("Resolution Settings"):
398
  z_points = st.slider("z grid points", min_value=1000, max_value=10000, value=5000, step=500, key="z_points")
399
- if st.button("Compute Complex Roots vs. z", key="tab2_button"):
 
 
 
 
 
 
 
400
  with col2:
401
  fig_im, fig_re = generate_root_plots(beta, y_2, z_a_2, z_min_2, z_max_2, z_points)
402
  if fig_im is not None and fig_re is not None:
403
  st.plotly_chart(fig_im, use_container_width=True)
404
  st.plotly_chart(fig_re, use_container_width=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
405
 
406
  # ----- Tab 3: Differential Analysis -----
407
  with tab3:
@@ -420,7 +512,6 @@ with tab3:
420
  # Add options for curve selection
421
  st.subheader("Curves to Analyze")
422
  analyze_upper_lower = st.checkbox("Upper-Lower Difference", value=True)
423
- analyze_low_y = st.checkbox("Low y Expression", value=False)
424
  analyze_high_y = st.checkbox("High y Expression", value=False)
425
  analyze_alt_low = st.checkbox("Alternate Low Expression", value=False)
426
 
@@ -443,18 +534,6 @@ with tab3:
443
  fig_diff.add_trace(go.Scatter(x=betas_diff, y=d2, mode="lines",
444
  name="Upper-Lower d²/dβ²", line=dict(color="magenta", dash='dot')))
445
 
446
- if analyze_low_y:
447
- low_y_curve = compute_low_y_curve(betas_diff, z_a_diff, y_diff)
448
- d1 = np.gradient(low_y_curve, betas_diff)
449
- d2 = np.gradient(d1, betas_diff)
450
-
451
- fig_diff.add_trace(go.Scatter(x=betas_diff, y=low_y_curve, mode="lines",
452
- name="Low y", line=dict(color="red", width=2)))
453
- fig_diff.add_trace(go.Scatter(x=betas_diff, y=d1, mode="lines",
454
- name="Low y d/dβ", line=dict(color="red", dash='dash')))
455
- fig_diff.add_trace(go.Scatter(x=betas_diff, y=d2, mode="lines",
456
- name="Low y d²/dβ²", line=dict(color="red", dash='dot')))
457
-
458
  if analyze_high_y:
459
  high_y_curve = compute_high_y_curve(betas_diff, z_a_diff, y_diff)
460
  d1 = np.gradient(high_y_curve, betas_diff)
 
88
  z_min_values.append(np.min(roots))
89
  z_max_values.append(np.max(roots))
90
  return betas, np.array(z_min_values), np.array(z_max_values)
91
+
92
  @st.cache_data
93
  def compute_low_y_curve(betas, z_a, y):
94
  """
 
144
  derivatives['lower'] = compute_derivatives(z_mins, betas)
145
 
146
  # Low y Expression
147
+ if low_y_curve is not None:
148
+ derivatives['low_y'] = compute_derivatives(low_y_curve, betas)
149
 
150
  # High y Expression
151
  derivatives['high_y'] = compute_derivatives(high_y_curve, betas)
 
200
  if np.isscalar(result):
201
  result = np.full_like(betas, result)
202
  return result
203
+
204
  def generate_z_vs_beta_plot(z_a, y, z_min, z_max, beta_steps, z_steps,
205
  s_num_expr=None, s_denom_expr=None,
206
  z_num_expr=None, z_denom_expr=None,
 
211
 
212
  betas = np.linspace(0, 1, beta_steps)
213
  betas, z_mins, z_maxs = sweep_beta_and_find_z_bounds(z_a, y, z_min, z_max, beta_steps, z_steps)
214
+
215
+ # Remove low_y_curve computation and display as requested
216
+ # low_y_curve = compute_low_y_curve(betas, z_a, y) # Commented out
217
+
218
  high_y_curve = compute_high_y_curve(betas, z_a, y)
219
  alt_low_expr = compute_alternate_low_expr(betas, z_a, y)
220
 
 
228
 
229
  # Compute derivatives if needed
230
  if show_derivatives:
231
+ derivatives = compute_all_derivatives(betas, z_mins, z_maxs, None, high_y_curve,
232
  alt_low_expr, custom_curve1, custom_curve2)
233
 
234
  fig = go.Figure()
 
238
  name="Upper z*(β)", line=dict(color='blue')))
239
  fig.add_trace(go.Scatter(x=betas, y=z_mins, mode="markers+lines",
240
  name="Lower z*(β)", line=dict(color='lightblue')))
241
+
242
+ # Remove low_y_curve trace as requested
243
+ # fig.add_trace(go.Scatter(x=betas, y=low_y_curve, mode="markers+lines",
244
+ # name="Low y Expression", line=dict(color='red')))
245
+
246
  fig.add_trace(go.Scatter(x=betas, y=high_y_curve, mode="markers+lines",
247
  name="High y Expression", line=dict(color='green')))
248
  fig.add_trace(go.Scatter(x=betas, y=alt_low_expr, mode="markers+lines",
 
260
  curve_info = [
261
  ('upper', 'Upper z*(β)', 'blue'),
262
  ('lower', 'Lower z*(β)', 'lightblue'),
263
+ # ('low_y', 'Low y', 'red'), # Removed as requested
264
  ('high_y', 'High y', 'green'),
265
  ('alt_low', 'Alt Low', 'orange')
266
  ]
 
290
  )
291
  )
292
  return fig
293
+
294
  def compute_cubic_roots(z, beta, z_a, y):
295
  """
296
  Compute the roots of the cubic equation for given parameters.
 
336
  xaxis_title="z", yaxis_title="Re{s}", hovermode="x unified")
337
  return fig_im, fig_re
338
 
339
+ # New function for the eigenvalue distribution
340
+ @st.cache_data
341
+ def compute_eigenvalue_distribution(z_a, y, beta, x_min, x_max, num_points, epsilon=1e-6):
342
+ """
343
+ Compute the eigenvalue distribution (ESD) of B_n as n → ∞.
344
+
345
+ B_n = (1/n)XX*
346
+ X is a p×n matrix with p/n → y as n → ∞
347
+ All elements of X are i.i.d. with distribution β·δ_a + (1-β)·δ_1
348
+ """
349
+ x_values = np.linspace(x_min, x_max, num_points)
350
+ density_values = np.zeros(num_points)
351
+
352
+ second_moment = beta * (z_a**2) + (1-beta) * 1
353
+
354
+ for i, x in enumerate(x_values):
355
+ z = complex(x, epsilon)
356
+
357
+ # Define the fixed-point equation for the Stieltjes transform
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
+ # Solve the fixed-point equation
370
+ initial_guess = [-0.1, -0.1] # Initial guess for the Stieltjes transform
371
+ m_solution = fsolve(fixed_point_equation, initial_guess)
372
+ m = complex(m_solution[0], m_solution[1])
373
+
374
+ # Compute the density using the Stieltjes inversion formula
375
+ density_values[i] = -1/np.pi * m.imag
376
+
377
+ # Ensure density is non-negative
378
+ density_values = np.maximum(density_values, 0)
379
+
380
+ return x_values, density_values
381
+
382
+ def generate_esd_plot(z_a, y, beta, x_min, x_max, num_points=1000):
383
+ """
384
+ Generate a plot of the eigenvalue distribution.
385
+ """
386
+ x_values, density_values = compute_eigenvalue_distribution(z_a, y, beta, x_min, x_max, num_points)
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="x",
395
+ yaxis_title="Density",
396
+ hovermode="x unified"
397
+ )
398
+
399
+ return fig
400
+
401
  # ----------------- Streamlit UI -----------------
402
  st.title("Cubic Root Analysis")
403
 
404
+ # Define three tabs (removed "Curve Intersections" tab)
405
+ tab1, tab2, tab3 = st.tabs(["z*(β) Curves", "Im{s} vs. z", "Differential Analysis"])
406
 
407
  # ----- Tab 1: z*(β) Curves -----
408
  with tab1:
 
443
  st.markdown("""
444
  - **Upper z*(β)** (Blue): Maximum z value where discriminant is zero
445
  - **Lower z*(β)** (Light Blue): Minimum z value where discriminant is zero
 
446
  - **High y Expression** (Green): Asymptotic approximation for high y values
447
  - **Alternate Low Expression** (Orange): Alternative asymptotic expression
448
  - **Custom Expression 1** (Purple): Result from user-defined s substituted into the main formula
 
455
  - Dotted lines: Second derivatives (d²/dβ²)
456
  """)
457
 
458
+ # ----- Tab 2: Im{s} vs. z and Eigenvalue Distribution -----
459
  with tab2:
460
+ st.header("Plot Complex Roots vs. z and Eigenvalue Distribution")
461
  col1, col2 = st.columns([1, 2])
462
  with col1:
463
  beta = st.number_input("β", value=0.5, min_value=0.0, max_value=1.0, key="beta_tab2")
 
467
  z_max_2 = st.number_input("z_max", value=10.0, key="z_max_tab2")
468
  with st.expander("Resolution Settings"):
469
  z_points = st.slider("z grid points", min_value=1000, max_value=10000, value=5000, step=500, key="z_points")
470
+
471
+ # Add new settings for eigenvalue distribution
472
+ st.subheader("Eigenvalue Distribution Settings")
473
+ x_min = st.number_input("x_min", value=0.0, key="x_min_esd")
474
+ x_max = st.number_input("x_max", value=5.0, key="x_max_esd")
475
+ num_points = st.slider("Number of points", min_value=100, max_value=2000, value=1000, step=100, key="num_points_esd")
476
+
477
+ if st.button("Compute", key="tab2_button"):
478
  with col2:
479
  fig_im, fig_re = generate_root_plots(beta, y_2, z_a_2, z_min_2, z_max_2, z_points)
480
  if fig_im is not None and fig_re is not None:
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
+ fig_esd = generate_esd_plot(z_a_2, y_2, beta, x_min, x_max, num_points)
486
+ st.plotly_chart(fig_esd, use_container_width=True)
487
+
488
+ st.markdown("""
489
+ ### Eigenvalue Distribution Explanation
490
+ This plot shows the limiting eigenvalue distribution of B_n = (1/n)XX* as n → ∞, where:
491
+ - X is a p×n matrix with p/n → y
492
+ - Elements of X are i.i.d. following distribution β·δ_a + (1-β)·δ_1
493
+ - a = z_a, y = y, β = β
494
+
495
+ The distribution is calculated using the Stieltjes transform approach.
496
+ """)
497
 
498
  # ----- Tab 3: Differential Analysis -----
499
  with tab3:
 
512
  # Add options for curve selection
513
  st.subheader("Curves to Analyze")
514
  analyze_upper_lower = st.checkbox("Upper-Lower Difference", value=True)
 
515
  analyze_high_y = st.checkbox("High y Expression", value=False)
516
  analyze_alt_low = st.checkbox("Alternate Low Expression", value=False)
517
 
 
534
  fig_diff.add_trace(go.Scatter(x=betas_diff, y=d2, mode="lines",
535
  name="Upper-Lower d²/dβ²", line=dict(color="magenta", dash='dot')))
536
 
 
 
 
 
 
 
 
 
 
 
 
 
537
  if analyze_high_y:
538
  high_y_curve = compute_high_y_curve(betas_diff, z_a_diff, y_diff)
539
  d1 = np.gradient(high_y_curve, betas_diff)