euler314 commited on
Commit
e0149a8
·
verified ·
1 Parent(s): 4c0789a

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +163 -96
app.py CHANGED
@@ -71,40 +71,50 @@ def find_z_at_discriminant_zero(z_a, y, beta, z_min, z_max, steps):
71
  return np.array(roots_found)
72
 
73
  @st.cache_data
74
- def compute_eigenvalue_support_boundaries(z_a, y, beta_steps, n_samples=1000, seeds=5):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
75
  """
76
  Compute the support boundaries of the eigenvalue distribution by directly
77
  finding the minimum and maximum eigenvalues of B_n = S_n T_n for different beta values.
78
-
79
- Parameters:
80
- -----------
81
- z_a : float
82
- Value for the delta mass at z_a
83
- y : float
84
- Aspect ratio p/n
85
- beta_steps : int
86
- Number of beta values to compute
87
- n_samples : int
88
- Sample size for each matrix
89
- seeds : int
90
- Number of different random seeds to average over
91
-
92
- Returns:
93
- --------
94
- betas, min_eigenvalues, max_eigenvalues - arrays representing the support boundaries
95
  """
96
- betas = np.linspace(0, 1, beta_steps)
97
- min_eigenvalues = np.zeros_like(betas)
98
- max_eigenvalues = np.zeros_like(betas)
99
 
100
- for i, beta in enumerate(betas):
 
 
 
 
 
 
 
 
101
  min_vals = []
102
  max_vals = []
103
 
104
  # Run multiple trials with different seeds for more stable results
105
  for seed in range(seeds):
106
  # Set random seed
107
- np.random.seed(seed)
108
 
109
  # Compute dimension p based on aspect ratio y
110
  n = n_samples
@@ -134,27 +144,11 @@ def compute_eigenvalue_support_boundaries(z_a, y, beta_steps, n_samples=1000, se
134
  min_eigenvalues[i] = np.mean(min_vals)
135
  max_eigenvalues[i] = np.mean(max_vals)
136
 
137
- return betas, min_eigenvalues, max_eigenvalues
138
-
139
- @st.cache_data
140
- def sweep_beta_and_find_z_bounds(z_a, y, z_min, z_max, beta_steps, z_steps):
141
- """
142
- For each beta in [0,1] (with beta_steps points), find the minimum and maximum z
143
- for which the discriminant is zero.
144
- Returns: betas, lower z*(β) values, and upper z*(β) values.
145
- """
146
- betas = np.linspace(0, 1, beta_steps)
147
- z_min_values = []
148
- z_max_values = []
149
- for b in betas:
150
- roots = find_z_at_discriminant_zero(z_a, y, b, z_min, z_max, z_steps)
151
- if len(roots) == 0:
152
- z_min_values.append(np.nan)
153
- z_max_values.append(np.nan)
154
- else:
155
- z_min_values.append(np.min(roots))
156
- z_max_values.append(np.max(roots))
157
- return betas, np.array(z_min_values), np.array(z_max_values)
158
 
159
  @st.cache_data
160
  def compute_high_y_curve(betas, z_a, y):
@@ -314,20 +308,25 @@ def compute_custom_expression(betas, z_a, y, s_num_expr, s_denom_expr, is_s_base
314
  def generate_z_vs_beta_plot(z_a, y, z_min, z_max, beta_steps, z_steps,
315
  s_num_expr=None, s_denom_expr=None,
316
  z_num_expr=None, z_denom_expr=None,
317
- show_derivatives=False, use_eigenvalue_method=False):
 
 
 
318
  if z_a <= 0 or y <= 0 or z_min >= z_max:
319
  st.error("Invalid input parameters.")
320
  return None
321
 
322
- # Get beta values and curves based on method
 
323
  if use_eigenvalue_method:
324
- # Use direct eigenvalue computation method to find support boundaries
325
- betas, z_mins, z_maxs = compute_eigenvalue_support_boundaries(z_a, y, beta_steps)
 
 
326
  else:
327
- # Use discriminant method
328
  betas, z_mins, z_maxs = sweep_beta_and_find_z_bounds(z_a, y, z_min, z_max, beta_steps, z_steps)
329
-
330
- # Compute other curves
331
  high_y_curve = compute_high_y_curve(betas, z_a, y)
332
  alt_low_expr = compute_alternate_low_expr(betas, z_a, y)
333
 
@@ -354,11 +353,27 @@ def generate_z_vs_beta_plot(z_a, y, z_min, z_max, beta_steps, z_steps,
354
  fig = go.Figure()
355
 
356
  # Original curves
357
- line_name_suffix = " (Eigenvalue Method)" if use_eigenvalue_method else ""
358
- fig.add_trace(go.Scatter(x=betas, y=z_maxs, mode="markers+lines",
359
- name="Upper z*(β)" + line_name_suffix, line=dict(color='blue')))
360
- fig.add_trace(go.Scatter(x=betas, y=z_mins, mode="markers+lines",
361
- name="Lower z*(β)" + line_name_suffix, line=dict(color='blue')))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
362
  # Removed the Low y Expression trace
363
  fig.add_trace(go.Scatter(x=betas, y=high_y_curve, mode="markers+lines",
364
  name="High y Expression", line=dict(color='green')))
@@ -381,8 +396,8 @@ def generate_z_vs_beta_plot(z_a, y, z_min, z_max, beta_steps, z_steps,
381
  if show_derivatives:
382
  # First derivatives
383
  curve_info = [
384
- ('upper', 'Upper z*(β)', 'blue'),
385
- ('lower', 'Lower z*(β)', 'lightblue'),
386
  # Removed low_y curve
387
  ('high_y', 'High y', 'green'),
388
  ('alt_low', 'Alt Low', 'orange')
@@ -409,9 +424,9 @@ def generate_z_vs_beta_plot(z_a, y, z_min, z_max, beta_steps, z_steps,
409
  fig.add_trace(go.Scatter(x=betas, y=min_t_derivatives[1], mode="lines",
410
  name="Min t d²/dβ²", line=dict(color='orange', dash='dot')))
411
 
412
- method_name = "Eigenvalue Method" if use_eigenvalue_method else "Discriminant Method"
413
  fig.update_layout(
414
- title=f"Curves vs β: z*(β) Boundaries and Asymptotic Expressions ({method_name})",
 
415
  xaxis_title="β",
416
  yaxis_title="Value",
417
  hovermode="x unified",
@@ -544,19 +559,32 @@ tab1, tab2, tab3 = st.tabs(["z*(β) Curves", "Im{s} vs. z", "Differential Analys
544
 
545
  # ----- Tab 1: z*(β) Curves -----
546
  with tab1:
547
- st.header("Find z Values where Cubic Roots Transition Between Real and Complex")
548
  col1, col2 = st.columns([1, 2])
549
  with col1:
550
  z_a_1 = st.number_input("z_a", value=1.0, key="z_a_1")
551
  y_1 = st.number_input("y", value=1.0, key="y_1")
552
  z_min_1 = st.number_input("z_min", value=-10.0, key="z_min_1")
553
  z_max_1 = st.number_input("z_max", value=10.0, key="z_max_1")
554
- with st.expander("Resolution Settings"):
555
- beta_steps = st.slider("β steps", min_value=51, max_value=501, value=201, step=50, key="beta_steps")
556
- z_steps = st.slider("z grid steps", min_value=1000, max_value=100000, value=50000, step=1000, key="z_steps")
557
 
558
- # Add option to use eigenvalue method
559
- use_eigenvalue_method = st.checkbox("Use Eigenvalue Method", value=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
560
 
561
  st.subheader("Custom Expression 1 (s-based)")
562
  st.markdown("""Enter expressions for s = numerator/denominator
@@ -574,24 +602,44 @@ with tab1:
574
 
575
  show_derivatives = st.checkbox("Show derivatives", value=False)
576
 
577
- if st.button("Compute z vs. β Curves", key="tab1_button"):
578
  with col2:
579
- fig = generate_z_vs_beta_plot(z_a_1, y_1, z_min_1, z_max_1, beta_steps, z_steps,
580
- s_num, s_denom, z_num, z_denom, show_derivatives, use_eigenvalue_method)
 
 
 
 
 
 
 
 
 
581
  if fig is not None:
582
  st.plotly_chart(fig, use_container_width=True)
583
- method_used = "Eigenvalue Method" if use_eigenvalue_method else "Discriminant Method"
584
- st.markdown(f"### Curve Explanations (using {method_used})")
585
- st.markdown("""
586
- - **Upper z*(β)** (Blue): Maximum z value where roots transition between real and complex
587
- - **Lower z*(β)** (Light Blue): Minimum z value where roots transition between real and complex
588
- - **High y Expression** (Green): Asymptotic approximation for high y values
589
- - **Low Expression** (Orange): Alternative asymptotic expression
590
- - **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)}$
591
- - **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)}$
592
- - **Custom Expression 1** (Purple): Result from user-defined s substituted into the main formula
593
- - **Custom Expression 2** (Magenta): Direct z(β) expression
594
- """)
 
 
 
 
 
 
 
 
 
 
 
595
  if show_derivatives:
596
  st.markdown("""
597
  Derivatives are shown as:
@@ -651,12 +699,27 @@ with tab3:
651
  y_diff = st.number_input("y", value=1.0, key="y_diff")
652
  z_min_diff = st.number_input("z_min", value=-10.0, key="z_min_diff")
653
  z_max_diff = st.number_input("z_max", value=10.0, key="z_max_diff")
654
- with st.expander("Resolution Settings"):
655
- beta_steps_diff = st.slider("β steps", min_value=51, max_value=501, value=201, step=50, key="beta_steps_diff")
656
- z_steps_diff = st.slider("z grid steps", min_value=1000, max_value=100000, value=50000, step=1000, key="z_steps_diff")
657
 
658
- # Add option for eigenvalue method
659
- use_eigenvalue_diff = st.checkbox("Use Eigenvalue Method", value=False, key="use_eigenvalue_diff")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
660
 
661
  # Add options for curve selection
662
  st.subheader("Curves to Analyze")
@@ -666,11 +729,16 @@ with tab3:
666
 
667
  if st.button("Compute Differentials", key="tab3_button"):
668
  with col2:
669
- # Use eigenvalue method if selected
670
- if use_eigenvalue_diff:
671
- betas_diff, lower_vals, upper_vals = compute_eigenvalue_support_boundaries(z_a_diff, y_diff, beta_steps_diff)
 
 
 
 
672
  else:
673
- betas_diff, lower_vals, upper_vals = sweep_beta_and_find_z_bounds(z_a_diff, y_diff, z_min_diff, z_max_diff, beta_steps_diff, z_steps_diff)
 
674
 
675
  # Create figure
676
  fig_diff = go.Figure()
@@ -680,13 +748,12 @@ with tab3:
680
  d1 = np.gradient(diff_curve, betas_diff)
681
  d2 = np.gradient(d1, betas_diff)
682
 
683
- method_suffix = " (Eigenvalue)" if use_eigenvalue_diff else ""
684
  fig_diff.add_trace(go.Scatter(x=betas_diff, y=diff_curve, mode="lines",
685
- name="Upper-Lower Difference" + method_suffix, line=dict(color="magenta", width=2)))
686
  fig_diff.add_trace(go.Scatter(x=betas_diff, y=d1, mode="lines",
687
- name="Upper-Lower d/dβ" + method_suffix, line=dict(color="magenta", dash='dash')))
688
  fig_diff.add_trace(go.Scatter(x=betas_diff, y=d2, mode="lines",
689
- name="Upper-Lower d²/dβ²" + method_suffix, line=dict(color="magenta", dash='dot')))
690
 
691
  if analyze_high_y:
692
  high_y_curve = compute_high_y_curve(betas_diff, z_a_diff, y_diff)
@@ -712,9 +779,9 @@ with tab3:
712
  fig_diff.add_trace(go.Scatter(x=betas_diff, y=d2, mode="lines",
713
  name="Alt Low d²/dβ²", line=dict(color="orange", dash='dot')))
714
 
715
- method_name = "Eigenvalue Method" if use_eigenvalue_diff else "Discriminant Method"
716
  fig_diff.update_layout(
717
- title=f"Differential Analysis vs. β ({method_name})",
 
718
  xaxis_title="β",
719
  yaxis_title="Value",
720
  hovermode="x unified",
 
71
  return np.array(roots_found)
72
 
73
  @st.cache_data
74
+ def sweep_beta_and_find_z_bounds(z_a, y, z_min, z_max, beta_steps, z_steps):
75
+ """
76
+ For each beta in [0,1] (with beta_steps points), find the minimum and maximum z
77
+ for which the discriminant is zero.
78
+ Returns: betas, lower z*(β) values, and upper z*(β) values.
79
+ """
80
+ betas = np.linspace(0, 1, beta_steps)
81
+ z_min_values = []
82
+ z_max_values = []
83
+ for b in betas:
84
+ roots = find_z_at_discriminant_zero(z_a, y, b, z_min, z_max, z_steps)
85
+ if len(roots) == 0:
86
+ z_min_values.append(np.nan)
87
+ z_max_values.append(np.nan)
88
+ else:
89
+ z_min_values.append(np.min(roots))
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_eigenvalue_support_boundaries(z_a, y, beta_values, n_samples=1000, seeds=5):
95
  """
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
 
102
+ # Use a progress bar for Streamlit
103
+ progress_bar = st.progress(0)
104
+ status_text = st.empty()
105
+
106
+ for i, beta in enumerate(beta_values):
107
+ # Update progress
108
+ progress_bar.progress((i + 1) / len(beta_values))
109
+ status_text.text(f"Processing β = {beta:.2f} ({i+1}/{len(beta_values)})")
110
+
111
  min_vals = []
112
  max_vals = []
113
 
114
  # Run multiple trials with different seeds for more stable results
115
  for seed in range(seeds):
116
  # Set random seed
117
+ np.random.seed(seed * 100 + i)
118
 
119
  # Compute dimension p based on aspect ratio y
120
  n = n_samples
 
144
  min_eigenvalues[i] = np.mean(min_vals)
145
  max_eigenvalues[i] = np.mean(max_vals)
146
 
147
+ # Clear progress indicators
148
+ progress_bar.empty()
149
+ status_text.empty()
150
+
151
+ return min_eigenvalues, max_eigenvalues
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
152
 
153
  @st.cache_data
154
  def compute_high_y_curve(betas, z_a, y):
 
308
  def generate_z_vs_beta_plot(z_a, y, z_min, z_max, beta_steps, z_steps,
309
  s_num_expr=None, s_denom_expr=None,
310
  z_num_expr=None, z_denom_expr=None,
311
+ show_derivatives=False,
312
+ use_eigenvalue_method=True,
313
+ n_samples=1000,
314
+ seeds=5):
315
  if z_a <= 0 or y <= 0 or z_min >= z_max:
316
  st.error("Invalid input parameters.")
317
  return None
318
 
319
+ betas = np.linspace(0, 1, beta_steps)
320
+
321
  if use_eigenvalue_method:
322
+ # Use the eigenvalue method to compute boundaries
323
+ st.info("Computing eigenvalue support boundaries. This may take a moment...")
324
+ min_eigs, max_eigs = compute_eigenvalue_support_boundaries(z_a, y, betas, n_samples, seeds)
325
+ z_mins, z_maxs = min_eigs, max_eigs
326
  else:
327
+ # Use the original discriminant method
328
  betas, z_mins, z_maxs = sweep_beta_and_find_z_bounds(z_a, y, z_min, z_max, beta_steps, z_steps)
329
+
 
330
  high_y_curve = compute_high_y_curve(betas, z_a, y)
331
  alt_low_expr = compute_alternate_low_expr(betas, z_a, y)
332
 
 
353
  fig = go.Figure()
354
 
355
  # Original curves
356
+ if use_eigenvalue_method:
357
+ fig.add_trace(go.Scatter(x=betas, y=z_maxs, mode="markers+lines",
358
+ name="Upper Bound (Max Eigenvalue)", line=dict(color='blue')))
359
+ fig.add_trace(go.Scatter(x=betas, y=z_mins, mode="markers+lines",
360
+ name="Lower Bound (Min Eigenvalue)", line=dict(color='blue')))
361
+ # Add shaded region between curves
362
+ fig.add_trace(go.Scatter(
363
+ x=np.concatenate([betas, betas[::-1]]),
364
+ y=np.concatenate([z_maxs, z_mins[::-1]]),
365
+ fill='toself',
366
+ fillcolor='rgba(0,0,255,0.2)',
367
+ line=dict(color='rgba(255,255,255,0)'),
368
+ showlegend=False,
369
+ hoverinfo='skip'
370
+ ))
371
+ else:
372
+ fig.add_trace(go.Scatter(x=betas, y=z_maxs, mode="markers+lines",
373
+ name="Upper z*(β)", line=dict(color='blue')))
374
+ fig.add_trace(go.Scatter(x=betas, y=z_mins, mode="markers+lines",
375
+ name="Lower z*(β)", line=dict(color='blue')))
376
+
377
  # Removed the Low y Expression trace
378
  fig.add_trace(go.Scatter(x=betas, y=high_y_curve, mode="markers+lines",
379
  name="High y Expression", line=dict(color='green')))
 
396
  if show_derivatives:
397
  # First derivatives
398
  curve_info = [
399
+ ('upper', 'Upper Bound' if use_eigenvalue_method else 'Upper z*(β)', 'blue'),
400
+ ('lower', 'Lower Bound' if use_eigenvalue_method else 'Lower z*(β)', 'lightblue'),
401
  # Removed low_y curve
402
  ('high_y', 'High y', 'green'),
403
  ('alt_low', 'Alt Low', 'orange')
 
424
  fig.add_trace(go.Scatter(x=betas, y=min_t_derivatives[1], mode="lines",
425
  name="Min t d²/dβ²", line=dict(color='orange', dash='dot')))
426
 
 
427
  fig.update_layout(
428
+ title="Curves vs β: Eigenvalue Support Boundaries and Asymptotic Expressions" if use_eigenvalue_method
429
+ else "Curves vs β: z*(β) Boundaries and Asymptotic Expressions",
430
  xaxis_title="β",
431
  yaxis_title="Value",
432
  hovermode="x unified",
 
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
 
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,
610
+ s_num, s_denom, z_num, z_denom, show_derivatives,
611
+ use_eigenvalue_method=True, n_samples=n_samples,
612
+ seeds=seeds)
613
+ else:
614
+ fig = generate_z_vs_beta_plot(z_a_1, y_1, z_min_1, z_max_1, beta_steps, z_steps,
615
+ s_num, s_denom, z_num, z_denom, show_derivatives,
616
+ use_eigenvalue_method=False)
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:
 
699
  y_diff = st.number_input("y", value=1.0, key="y_diff")
700
  z_min_diff = st.number_input("z_min", value=-10.0, key="z_min_diff")
701
  z_max_diff = st.number_input("z_max", value=10.0, key="z_max_diff")
 
 
 
702
 
703
+ diff_method_type = st.radio(
704
+ "Boundary Calculation Method",
705
+ ["Eigenvalue Method", "Discriminant Method"],
706
+ index=0,
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")
714
+ diff_n_samples = st.slider("Matrix size (n)", min_value=100, max_value=2000, value=1000,
715
+ step=100, key="diff_n_samples")
716
+ diff_seeds = st.slider("Number of seeds", min_value=1, max_value=10, value=5, step=1,
717
+ key="diff_seeds")
718
+ else:
719
+ beta_steps_diff = st.slider("β steps", min_value=51, max_value=501, value=201, step=50,
720
+ key="beta_steps_diff")
721
+ z_steps_diff = st.slider("z grid steps", min_value=1000, max_value=100000, value=50000,
722
+ step=1000, key="z_steps_diff")
723
 
724
  # Add options for curve selection
725
  st.subheader("Curves to Analyze")
 
729
 
730
  if st.button("Compute Differentials", key="tab3_button"):
731
  with col2:
732
+ use_eigenvalue_method_diff = (diff_method_type == "Eigenvalue Method")
733
+
734
+ if use_eigenvalue_method_diff:
735
+ betas_diff = np.linspace(0, 1, beta_steps_diff)
736
+ st.info("Computing eigenvalue support boundaries. This may take a moment...")
737
+ lower_vals, upper_vals = compute_eigenvalue_support_boundaries(
738
+ z_a_diff, y_diff, betas_diff, diff_n_samples, diff_seeds)
739
  else:
740
+ betas_diff, lower_vals, upper_vals = sweep_beta_and_find_z_bounds(
741
+ z_a_diff, y_diff, z_min_diff, z_max_diff, beta_steps_diff, z_steps_diff)
742
 
743
  # Create figure
744
  fig_diff = go.Figure()
 
748
  d1 = np.gradient(diff_curve, betas_diff)
749
  d2 = np.gradient(d1, betas_diff)
750
 
 
751
  fig_diff.add_trace(go.Scatter(x=betas_diff, y=diff_curve, mode="lines",
752
+ name="Upper-Lower Difference", line=dict(color="magenta", width=2)))
753
  fig_diff.add_trace(go.Scatter(x=betas_diff, y=d1, mode="lines",
754
+ name="Upper-Lower d/dβ", line=dict(color="magenta", dash='dash')))
755
  fig_diff.add_trace(go.Scatter(x=betas_diff, y=d2, mode="lines",
756
+ name="Upper-Lower d²/dβ²", line=dict(color="magenta", dash='dot')))
757
 
758
  if analyze_high_y:
759
  high_y_curve = compute_high_y_curve(betas_diff, z_a_diff, y_diff)
 
779
  fig_diff.add_trace(go.Scatter(x=betas_diff, y=d2, mode="lines",
780
  name="Alt Low d²/dβ²", line=dict(color="orange", dash='dot')))
781
 
 
782
  fig_diff.update_layout(
783
+ title="Differential Analysis vs. β" +
784
+ (" (Eigenvalue Method)" if use_eigenvalue_method_diff else " (Discriminant Method)"),
785
  xaxis_title="β",
786
  yaxis_title="Value",
787
  hovermode="x unified",