euler314 commited on
Commit
675a582
·
verified ·
1 Parent(s): 2d93a46

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +129 -92
app.py CHANGED
@@ -96,6 +96,9 @@ def compute_eigenvalue_support_boundaries(z_a, y, beta_values, n_samples=100, se
96
  Compute the support boundaries of the eigenvalue distribution by directly
97
  finding the minimum and maximum eigenvalues of B_n = S_n T_n for different beta values.
98
  """
 
 
 
99
  min_eigenvalues = np.zeros_like(beta_values)
100
  max_eigenvalues = np.zeros_like(beta_values)
101
 
@@ -118,11 +121,16 @@ def compute_eigenvalue_support_boundaries(z_a, y, beta_values, n_samples=100, se
118
 
119
  # Compute dimension p based on aspect ratio y
120
  n = n_samples
121
- p = int(y * n)
122
 
123
  # Constructing T_n (Population / Shape Matrix)
124
- T_diag = np.where(np.random.rand(p) < beta, z_a, 1.0)
125
- T_n = np.diag(T_diag)
 
 
 
 
 
126
 
127
  # Generate the data matrix X with i.i.d. standard normal entries
128
  X = np.random.randn(p, n)
@@ -155,12 +163,15 @@ def compute_high_y_curve(betas, z_a, y):
155
  """
156
  Compute the "High y Expression" curve.
157
  """
 
 
 
158
  a = z_a
159
  betas = np.array(betas)
160
  denominator = 1 - 2*a
161
  if denominator == 0:
162
  return np.full_like(betas, np.nan)
163
- numerator = -4*a*(a-1)*y*betas - 2*a*y - 2*a*(2*a-1)
164
  return numerator/denominator
165
 
166
  def compute_alternate_low_expr(betas, z_a, y):
@@ -168,14 +179,20 @@ def compute_alternate_low_expr(betas, z_a, y):
168
  Compute the alternate low expression:
169
  (z_a*y*beta*(z_a-1) - 2*z_a*(1-y) - 2*z_a**2) / (2+2*z_a)
170
  """
 
 
 
171
  betas = np.array(betas)
172
- return (z_a * y * betas * (z_a - 1) - 2*z_a*(1 - y) - 2*z_a**2) / (2 + 2*z_a)
173
 
174
  @st.cache_data
175
  def compute_max_k_expression(betas, z_a, y, k_samples=1000):
176
  """
177
  Compute max_{k ∈ (0,∞)} (y*beta*(a-1)*k + (a*k+1)*((y-1)*k-1)) / ((a*k+1)*(k^2+k))
178
  """
 
 
 
179
  a = z_a
180
  # Sample k values on a logarithmic scale
181
  k_values = np.logspace(-3, 3, k_samples)
@@ -184,7 +201,7 @@ def compute_max_k_expression(betas, z_a, y, k_samples=1000):
184
  for i, beta in enumerate(betas):
185
  values = np.zeros_like(k_values)
186
  for j, k in enumerate(k_values):
187
- numerator = y*beta*(a-1)*k + (a*k+1)*((y-1)*k-1)
188
  denominator = (a*k+1)*(k**2+k)
189
  if abs(denominator) < 1e-10:
190
  values[j] = np.nan
@@ -204,6 +221,9 @@ def compute_min_t_expression(betas, z_a, y, t_samples=1000):
204
  """
205
  Compute min_{t ∈ (-1/a, 0)} (y*beta*(a-1)*t + (a*t+1)*((y-1)*t-1)) / ((a*t+1)*(t^2+t))
206
  """
 
 
 
207
  a = z_a
208
  if a <= 0:
209
  return np.full_like(betas, np.nan)
@@ -215,7 +235,7 @@ def compute_min_t_expression(betas, z_a, y, t_samples=1000):
215
  for i, beta in enumerate(betas):
216
  values = np.zeros_like(t_values)
217
  for j, t in enumerate(t_values):
218
- numerator = y*beta*(a-1)*t + (a*t+1)*((y-1)*t-1)
219
  denominator = (a*t+1)*(t**2+t)
220
  if abs(denominator) < 1e-10:
221
  values[j] = np.nan
@@ -272,6 +292,9 @@ def compute_custom_expression(betas, z_a, y, s_num_expr, s_denom_expr, is_s_base
272
  Compute custom curve. If is_s_based=True, compute using s substitution.
273
  Otherwise, compute direct z(β) expression.
274
  """
 
 
 
275
  beta_sym, z_a_sym, y_sym = sp.symbols("beta z_a y", positive=True)
276
  local_dict = {"beta": beta_sym, "z_a": z_a_sym, "y": y_sym, "sp": sp}
277
 
@@ -300,7 +323,7 @@ def compute_custom_expression(betas, z_a, y, s_num_expr, s_denom_expr, is_s_base
300
 
301
  final_func = sp.lambdify((beta_sym, z_a_sym, y_sym), final_expr, modules=["numpy"])
302
  with np.errstate(divide='ignore', invalid='ignore'):
303
- result = final_func(betas, z_a, y)
304
  if np.isscalar(result):
305
  result = np.full_like(betas, result)
306
  return result
@@ -444,9 +467,12 @@ def compute_cubic_roots(z, beta, z_a, y):
444
  """
445
  Compute the roots of the cubic equation for given parameters.
446
  """
 
 
 
447
  a = z * z_a
448
- b = z * z_a + z + z_a - z_a*y
449
- c = z + z_a + 1 - y*(beta*z_a + 1 - beta)
450
  d = 1
451
  coeffs = [a, b, c, d]
452
  roots = np.roots(coeffs)
@@ -489,29 +515,24 @@ def generate_root_plots(beta, y, z_a, z_min, z_max, n_points):
489
  def generate_eigenvalue_distribution(beta, y, z_a, n=1000, seed=42):
490
  """
491
  Generate the eigenvalue distribution of B_n = S_n T_n as n→∞
492
-
493
- Parameters:
494
- -----------
495
- beta : float
496
- Fraction of components equal to z_a
497
- y : float
498
- Aspect ratio p/n
499
- z_a : float
500
- Value for the delta mass at z_a
501
- n : int
502
- Number of samples
503
- seed : int
504
- Random seed for reproducibility
505
  """
 
 
 
506
  # Set random seed
507
  np.random.seed(seed)
508
 
509
  # Compute dimension p based on aspect ratio y
510
- p = int(y * n)
511
 
512
- # Constructing T_n (Population / Shape Matrix)
513
- T_diag = np.where(np.random.rand(p) < beta, z_a, 1.0)
514
- T_n = np.diag(T_diag)
 
 
 
 
 
515
 
516
  # Generate the data matrix X with i.i.d. standard normal entries
517
  X = np.random.randn(p, n)
@@ -559,34 +580,42 @@ tab1, tab2, tab3 = st.tabs(["z*(β) Curves", "Im{s} vs. z", "Differential Analys
559
 
560
  # ----- Tab 1: z*(β) Curves -----
561
  with tab1:
562
- st.header("Find Eigenvalue Support Boundaries")
563
- col1, col2 = st.columns([1, 2])
 
 
 
564
  with col1:
565
  z_a_1 = st.number_input("z_a", value=1.0, key="z_a_1")
566
  y_1 = st.number_input("y", value=1.0, key="y_1")
 
 
567
  z_min_1 = st.number_input("z_min", value=-10.0, key="z_min_1")
568
  z_max_1 = st.number_input("z_max", value=10.0, key="z_max_1")
569
-
 
570
  method_type = st.radio(
571
- "Boundary Calculation Method",
572
  ["Eigenvalue Method", "Discriminant Method"],
573
  index=0 # Default to eigenvalue method
574
  )
575
-
576
- with st.expander("Method Settings"):
577
- if method_type == "Eigenvalue Method":
578
- beta_steps = st.slider("β steps", min_value=21, max_value=101, value=51, step=10,
579
- key="beta_steps_eigen")
580
- n_samples = st.slider("Matrix size (n)", min_value=100, max_value=2000, value=1000,
581
- step=100)
582
- seeds = st.slider("Number of seeds", min_value=1, max_value=10, value=5, step=1)
583
- else:
584
- beta_steps = st.slider("β steps", min_value=51, max_value=501, value=201, step=50,
585
- key="beta_steps")
586
- z_steps = st.slider("z grid steps", min_value=1000, max_value=100000, value=50000,
587
- step=1000, key="z_steps")
588
-
589
- st.subheader("Custom Expression 1 (s-based)")
 
 
590
  st.markdown("""Enter expressions for s = numerator/denominator
591
  (using variables `y`, `beta`, `z_a`, and `sqrt()`)""")
592
  st.latex(r"\text{This s will be inserted into:}")
@@ -594,16 +623,19 @@ with tab1:
594
  s_num = st.text_input("s numerator", value="", key="s_num")
595
  s_denom = st.text_input("s denominator", value="", key="s_denom")
596
 
597
- st.subheader("Custom Expression 2 (direct z(β))")
598
  st.markdown("""Enter direct expression for z(β) = numerator/denominator
599
  (using variables `y`, `beta`, `z_a`, and `sqrt()`)""")
600
  z_num = st.text_input("z(β) numerator", value="", key="z_num")
601
  z_denom = st.text_input("z(β) denominator", value="", key="z_denom")
602
 
 
 
603
  show_derivatives = st.checkbox("Show derivatives", value=False)
604
 
 
605
  if st.button("Compute Curves", key="tab1_button"):
606
- with col2:
607
  use_eigenvalue_method = (method_type == "Eigenvalue Method")
608
  if use_eigenvalue_method:
609
  fig = generate_z_vs_beta_plot(z_a_1, y_1, z_min_1, z_max_1, beta_steps, None,
@@ -617,35 +649,37 @@ with tab1:
617
 
618
  if fig is not None:
619
  st.plotly_chart(fig, use_container_width=True)
620
- st.markdown("### Curve Explanations")
621
- if use_eigenvalue_method:
622
- st.markdown("""
623
- - **Upper/Lower Bounds** (Blue): Maximum/minimum eigenvalues of B_n = S_n T_n
624
- - **Shaded Region**: Eigenvalue support region
625
- - **High y Expression** (Green): Asymptotic approximation for high y values
626
- - **Low Expression** (Orange): Alternative asymptotic expression
627
- - **Max k Expression** (Red): $\\max_{k \\in (0,\\infty)} \\frac{y\\beta (a-1)k + \\bigl(ak+1\\bigr)\\bigl((y-1)k-1\\bigr)}{(ak+1)(k^2+k)}$
628
- - **Min t Expression** (Orange): $\\min_{t \\in \\left(-\\frac{1}{a},\\, 0\\right)} \\frac{y\\beta (a-1)t + \\bigl(at+1\\bigr)\\bigl((y-1)t-1\\bigr)}{(at+1)(t^2+t)}$
629
- - **Custom Expression 1** (Purple): Result from user-defined s substituted into the main formula
630
- - **Custom Expression 2** (Magenta): Direct z(β) expression
631
- """)
632
- else:
633
- st.markdown("""
634
- - **Upper z*(β)** (Blue): Maximum z value where discriminant is zero
635
- - **Lower z*(β)** (Light Blue): Minimum z value where discriminant is zero
636
- - **High y Expression** (Green): Asymptotic approximation for high y values
637
- - **Low Expression** (Orange): Alternative asymptotic expression
638
- - **Max k Expression** (Red): $\\max_{k \\in (0,\\infty)} \\frac{y\\beta (a-1)k + \\bigl(ak+1\\bigr)\\bigl((y-1)k-1\\bigr)}{(ak+1)(k^2+k)}$
639
- - **Min t Expression** (Orange): $\\min_{t \\in \\left(-\\frac{1}{a},\\, 0\\right)} \\frac{y\\beta (a-1)t + \\bigl(at+1\\bigr)\\bigl((y-1)t-1\\bigr)}{(at+1)(t^2+t)}$
640
- - **Custom Expression 1** (Purple): Result from user-defined s substituted into the main formula
641
- - **Custom Expression 2** (Magenta): Direct z(β) expression
642
- """)
643
- if show_derivatives:
644
- st.markdown("""
645
- Derivatives are shown as:
646
- - Dashed lines: First derivatives (d/dβ)
647
- - Dotted lines: Second derivatives (d²/dβ²)
648
- """)
 
 
649
 
650
  # ----- Tab 2: Im{s} vs. z -----
651
  with tab2:
@@ -657,7 +691,7 @@ with tab2:
657
  z_a_2 = st.number_input("z_a", value=1.0, key="z_a_tab2")
658
  z_min_2 = st.number_input("z_min", value=-10.0, key="z_min_tab2")
659
  z_max_2 = st.number_input("z_max", value=10.0, key="z_max_tab2")
660
- with st.expander("Resolution Settings"):
661
  z_points = st.slider("z grid points", min_value=1000, max_value=10000, value=5000, step=500, key="z_points")
662
  if st.button("Compute Complex Roots vs. z", key="tab2_button"):
663
  with col2:
@@ -671,12 +705,13 @@ with tab2:
671
 
672
  # Add eigenvalue distribution section
673
  st.header("Eigenvalue Distribution for B_n = S_n T_n")
674
- st.markdown("""
675
- This simulation generates the eigenvalue distribution of B_n as n→∞, where:
676
- - B_n = (1/n)XX* with X being a p×n matrix
677
- - p/n y as n→∞
678
- - All elements of X are i.i.d with distribution β·δ(z_a) + (1-β)·δ(1)
679
- """)
 
680
 
681
  col_eigen1, col_eigen2 = st.columns([1, 2])
682
  with col_eigen1:
@@ -692,7 +727,9 @@ with tab2:
692
  # ----- Tab 3: Differential Analysis -----
693
  with tab3:
694
  st.header("Differential Analysis vs. β")
695
- st.markdown("This page shows the difference between the Upper (blue) and Lower (lightblue) z*(β) curves, along with their first and second derivatives with respect to β.")
 
 
696
  col1, col2 = st.columns([1, 2])
697
  with col1:
698
  z_a_diff = st.number_input("z_a", value=1.0, key="z_a_diff")
@@ -707,7 +744,7 @@ with tab3:
707
  key="diff_method_type"
708
  )
709
 
710
- with st.expander("Resolution Settings"):
711
  if diff_method_type == "Eigenvalue Method":
712
  beta_steps_diff = st.slider("β steps", min_value=21, max_value=101, value=51, step=10,
713
  key="beta_steps_diff_eigen")
@@ -795,9 +832,9 @@ with tab3:
795
  )
796
  st.plotly_chart(fig_diff, use_container_width=True)
797
 
798
- st.markdown("""
799
- ### Curve Types
800
- - Solid lines: Original curves
801
- - Dashed lines: First derivatives (d/dβ)
802
- - Dotted lines: Second derivatives (d²/dβ²)
803
- """)
 
96
  Compute the support boundaries of the eigenvalue distribution by directly
97
  finding the minimum and maximum eigenvalues of B_n = S_n T_n for different beta values.
98
  """
99
+ # Apply the condition for y
100
+ y_effective = y if y > 1 else 1/y
101
+
102
  min_eigenvalues = np.zeros_like(beta_values)
103
  max_eigenvalues = np.zeros_like(beta_values)
104
 
 
121
 
122
  # Compute dimension p based on aspect ratio y
123
  n = n_samples
124
+ p = int(y_effective * n)
125
 
126
  # Constructing T_n (Population / Shape Matrix)
127
+ k = int(np.floor(beta * p))
128
+ diag_entries = np.concatenate([
129
+ np.full(k, z_a),
130
+ np.full(p - k, 1.0)
131
+ ])
132
+ np.random.shuffle(diag_entries)
133
+ T_n = np.diag(diag_entries)
134
 
135
  # Generate the data matrix X with i.i.d. standard normal entries
136
  X = np.random.randn(p, n)
 
163
  """
164
  Compute the "High y Expression" curve.
165
  """
166
+ # Apply the condition for y
167
+ y_effective = y if y > 1 else 1/y
168
+
169
  a = z_a
170
  betas = np.array(betas)
171
  denominator = 1 - 2*a
172
  if denominator == 0:
173
  return np.full_like(betas, np.nan)
174
+ numerator = -4*a*(a-1)*y_effective*betas - 2*a*y_effective - 2*a*(2*a-1)
175
  return numerator/denominator
176
 
177
  def compute_alternate_low_expr(betas, z_a, y):
 
179
  Compute the alternate low expression:
180
  (z_a*y*beta*(z_a-1) - 2*z_a*(1-y) - 2*z_a**2) / (2+2*z_a)
181
  """
182
+ # Apply the condition for y
183
+ y_effective = y if y > 1 else 1/y
184
+
185
  betas = np.array(betas)
186
+ return (z_a * y_effective * betas * (z_a - 1) - 2*z_a*(1 - y_effective) - 2*z_a**2) / (2 + 2*z_a)
187
 
188
  @st.cache_data
189
  def compute_max_k_expression(betas, z_a, y, k_samples=1000):
190
  """
191
  Compute max_{k ∈ (0,∞)} (y*beta*(a-1)*k + (a*k+1)*((y-1)*k-1)) / ((a*k+1)*(k^2+k))
192
  """
193
+ # Apply the condition for y
194
+ y_effective = y if y > 1 else 1/y
195
+
196
  a = z_a
197
  # Sample k values on a logarithmic scale
198
  k_values = np.logspace(-3, 3, k_samples)
 
201
  for i, beta in enumerate(betas):
202
  values = np.zeros_like(k_values)
203
  for j, k in enumerate(k_values):
204
+ numerator = y_effective*beta*(a-1)*k + (a*k+1)*((y_effective-1)*k-1)
205
  denominator = (a*k+1)*(k**2+k)
206
  if abs(denominator) < 1e-10:
207
  values[j] = np.nan
 
221
  """
222
  Compute min_{t ∈ (-1/a, 0)} (y*beta*(a-1)*t + (a*t+1)*((y-1)*t-1)) / ((a*t+1)*(t^2+t))
223
  """
224
+ # Apply the condition for y
225
+ y_effective = y if y > 1 else 1/y
226
+
227
  a = z_a
228
  if a <= 0:
229
  return np.full_like(betas, np.nan)
 
235
  for i, beta in enumerate(betas):
236
  values = np.zeros_like(t_values)
237
  for j, t in enumerate(t_values):
238
+ numerator = y_effective*beta*(a-1)*t + (a*t+1)*((y_effective-1)*t-1)
239
  denominator = (a*t+1)*(t**2+t)
240
  if abs(denominator) < 1e-10:
241
  values[j] = np.nan
 
292
  Compute custom curve. If is_s_based=True, compute using s substitution.
293
  Otherwise, compute direct z(β) expression.
294
  """
295
+ # Apply the condition for y
296
+ y_effective = y if y > 1 else 1/y
297
+
298
  beta_sym, z_a_sym, y_sym = sp.symbols("beta z_a y", positive=True)
299
  local_dict = {"beta": beta_sym, "z_a": z_a_sym, "y": y_sym, "sp": sp}
300
 
 
323
 
324
  final_func = sp.lambdify((beta_sym, z_a_sym, y_sym), final_expr, modules=["numpy"])
325
  with np.errstate(divide='ignore', invalid='ignore'):
326
+ result = final_func(betas, z_a, y_effective)
327
  if np.isscalar(result):
328
  result = np.full_like(betas, result)
329
  return result
 
467
  """
468
  Compute the roots of the cubic equation for given parameters.
469
  """
470
+ # Apply the condition for y
471
+ y_effective = y if y > 1 else 1/y
472
+
473
  a = z * z_a
474
+ b = z * z_a + z + z_a - z_a*y_effective
475
+ c = z + z_a + 1 - y_effective*(beta*z_a + 1 - beta)
476
  d = 1
477
  coeffs = [a, b, c, d]
478
  roots = np.roots(coeffs)
 
515
  def generate_eigenvalue_distribution(beta, y, z_a, n=1000, seed=42):
516
  """
517
  Generate the eigenvalue distribution of B_n = S_n T_n as n→∞
 
 
 
 
 
 
 
 
 
 
 
 
 
518
  """
519
+ # Apply the condition for y
520
+ y_effective = y if y > 1 else 1/y
521
+
522
  # Set random seed
523
  np.random.seed(seed)
524
 
525
  # Compute dimension p based on aspect ratio y
526
+ p = int(y_effective * n)
527
 
528
+ # Constructing T_n (Population / Shape Matrix) - using the approach from the second script
529
+ k = int(np.floor(beta * p))
530
+ diag_entries = np.concatenate([
531
+ np.full(k, z_a),
532
+ np.full(p - k, 1.0)
533
+ ])
534
+ np.random.shuffle(diag_entries)
535
+ T_n = np.diag(diag_entries)
536
 
537
  # Generate the data matrix X with i.i.d. standard normal entries
538
  X = np.random.randn(p, n)
 
580
 
581
  # ----- Tab 1: z*(β) Curves -----
582
  with tab1:
583
+ st.header("Eigenvalue Support Boundaries")
584
+
585
+ # Cleaner layout with better column organization
586
+ col1, col2, col3 = st.columns([1, 1, 2])
587
+
588
  with col1:
589
  z_a_1 = st.number_input("z_a", value=1.0, key="z_a_1")
590
  y_1 = st.number_input("y", value=1.0, key="y_1")
591
+
592
+ with col2:
593
  z_min_1 = st.number_input("z_min", value=-10.0, key="z_min_1")
594
  z_max_1 = st.number_input("z_max", value=10.0, key="z_max_1")
595
+
596
+ with col1:
597
  method_type = st.radio(
598
+ "Calculation Method",
599
  ["Eigenvalue Method", "Discriminant Method"],
600
  index=0 # Default to eigenvalue method
601
  )
602
+
603
+ # Advanced settings in collapsed expanders
604
+ with st.expander("Method Settings", expanded=False):
605
+ if method_type == "Eigenvalue Method":
606
+ beta_steps = st.slider("β steps", min_value=21, max_value=101, value=51, step=10,
607
+ key="beta_steps_eigen")
608
+ n_samples = st.slider("Matrix size (n)", min_value=100, max_value=2000, value=1000,
609
+ step=100)
610
+ seeds = st.slider("Number of seeds", min_value=1, max_value=10, value=5, step=1)
611
+ else:
612
+ beta_steps = st.slider("β steps", min_value=51, max_value=501, value=201, step=50,
613
+ key="beta_steps")
614
+ z_steps = st.slider("z grid steps", min_value=1000, max_value=100000, value=50000,
615
+ step=1000, key="z_steps")
616
+
617
+ # Custom expressions collapsed by default
618
+ with st.expander("Custom Expression 1 (s-based)", expanded=False):
619
  st.markdown("""Enter expressions for s = numerator/denominator
620
  (using variables `y`, `beta`, `z_a`, and `sqrt()`)""")
621
  st.latex(r"\text{This s will be inserted into:}")
 
623
  s_num = st.text_input("s numerator", value="", key="s_num")
624
  s_denom = st.text_input("s denominator", value="", key="s_denom")
625
 
626
+ with st.expander("Custom Expression 2 (direct z(β))", expanded=False):
627
  st.markdown("""Enter direct expression for z(β) = numerator/denominator
628
  (using variables `y`, `beta`, `z_a`, and `sqrt()`)""")
629
  z_num = st.text_input("z(β) numerator", value="", key="z_num")
630
  z_denom = st.text_input("z(β) denominator", value="", key="z_denom")
631
 
632
+ # Move show_derivatives to main UI level for better visibility
633
+ with col2:
634
  show_derivatives = st.checkbox("Show derivatives", value=False)
635
 
636
+ # Compute button
637
  if st.button("Compute Curves", key="tab1_button"):
638
+ with col3:
639
  use_eigenvalue_method = (method_type == "Eigenvalue Method")
640
  if use_eigenvalue_method:
641
  fig = generate_z_vs_beta_plot(z_a_1, y_1, z_min_1, z_max_1, beta_steps, None,
 
649
 
650
  if fig is not None:
651
  st.plotly_chart(fig, use_container_width=True)
652
+
653
+ # Curve explanations in collapsed expander
654
+ with st.expander("Curve Explanations", expanded=False):
655
+ if use_eigenvalue_method:
656
+ st.markdown("""
657
+ - **Upper/Lower Bounds** (Blue): Maximum/minimum eigenvalues of B_n = S_n T_n
658
+ - **Shaded Region**: Eigenvalue support region
659
+ - **High y Expression** (Green): Asymptotic approximation for high y values
660
+ - **Low Expression** (Orange): Alternative asymptotic expression
661
+ - **Max k Expression** (Red): $\\max_{k \\in (0,\\infty)} \\frac{y\\beta (a-1)k + \\bigl(ak+1\\bigr)\\bigl((y-1)k-1\\bigr)}{(ak+1)(k^2+k)}$
662
+ - **Min t Expression** (Orange): $\\min_{t \\in \\left(-\\frac{1}{a},\\, 0\\right)} \\frac{y\\beta (a-1)t + \\bigl(at+1\\bigr)\\bigl((y-1)t-1\\bigr)}{(at+1)(t^2+t)}$
663
+ - **Custom Expression 1** (Purple): Result from user-defined s substituted into the main formula
664
+ - **Custom Expression 2** (Magenta): Direct z(β) expression
665
+ """)
666
+ else:
667
+ st.markdown("""
668
+ - **Upper z*(β)** (Blue): Maximum z value where discriminant is zero
669
+ - **Lower z*(β)** (Light Blue): Minimum z value where discriminant is zero
670
+ - **High y Expression** (Green): Asymptotic approximation for high y values
671
+ - **Low Expression** (Orange): Alternative asymptotic expression
672
+ - **Max k Expression** (Red): $\\max_{k \\in (0,\\infty)} \\frac{y\\beta (a-1)k + \\bigl(ak+1\\bigr)\\bigl((y-1)k-1\\bigr)}{(ak+1)(k^2+k)}$
673
+ - **Min t Expression** (Orange): $\\min_{t \\in \\left(-\\frac{1}{a},\\, 0\\right)} \\frac{y\\beta (a-1)t + \\bigl(at+1\\bigr)\\bigl((y-1)t-1\\bigr)}{(at+1)(t^2+t)}$
674
+ - **Custom Expression 1** (Purple): Result from user-defined s substituted into the main formula
675
+ - **Custom Expression 2** (Magenta): Direct z(β) expression
676
+ """)
677
+ if show_derivatives:
678
+ st.markdown("""
679
+ Derivatives are shown as:
680
+ - Dashed lines: First derivatives (d/dβ)
681
+ - Dotted lines: Second derivatives (d²/dβ²)
682
+ """)
683
 
684
  # ----- Tab 2: Im{s} vs. z -----
685
  with tab2:
 
691
  z_a_2 = st.number_input("z_a", value=1.0, key="z_a_tab2")
692
  z_min_2 = st.number_input("z_min", value=-10.0, key="z_min_tab2")
693
  z_max_2 = st.number_input("z_max", value=10.0, key="z_max_tab2")
694
+ with st.expander("Resolution Settings", expanded=False):
695
  z_points = st.slider("z grid points", min_value=1000, max_value=10000, value=5000, step=500, key="z_points")
696
  if st.button("Compute Complex Roots vs. z", key="tab2_button"):
697
  with col2:
 
705
 
706
  # Add eigenvalue distribution section
707
  st.header("Eigenvalue Distribution for B_n = S_n T_n")
708
+ with st.expander("Simulation Information", expanded=False):
709
+ st.markdown("""
710
+ This simulation generates the eigenvalue distribution of B_n as n→∞, where:
711
+ - B_n = (1/n)XX* with X being a p×n matrix
712
+ - p/n y as n→∞
713
+ - All elements of X are i.i.d with distribution β·δ(z_a) + (1-β)·δ(1)
714
+ """)
715
 
716
  col_eigen1, col_eigen2 = st.columns([1, 2])
717
  with col_eigen1:
 
727
  # ----- Tab 3: Differential Analysis -----
728
  with tab3:
729
  st.header("Differential Analysis vs. β")
730
+ with st.expander("Description", expanded=False):
731
+ st.markdown("This page shows the difference between the Upper (blue) and Lower (lightblue) z*(β) curves, along with their first and second derivatives with respect to β.")
732
+
733
  col1, col2 = st.columns([1, 2])
734
  with col1:
735
  z_a_diff = st.number_input("z_a", value=1.0, key="z_a_diff")
 
744
  key="diff_method_type"
745
  )
746
 
747
+ with st.expander("Resolution Settings", expanded=False):
748
  if diff_method_type == "Eigenvalue Method":
749
  beta_steps_diff = st.slider("β steps", min_value=21, max_value=101, value=51, step=10,
750
  key="beta_steps_diff_eigen")
 
832
  )
833
  st.plotly_chart(fig_diff, use_container_width=True)
834
 
835
+ with st.expander("Curve Types", expanded=False):
836
+ st.markdown("""
837
+ - Solid lines: Original curves
838
+ - Dashed lines: First derivatives (d/dβ)
839
+ - Dotted lines: Second derivatives (d²/dβ²)
840
+ """)