Spaces:
Running
Running
Update app.py
Browse files
app.py
CHANGED
@@ -70,6 +70,72 @@ def find_z_at_discriminant_zero(z_a, y, beta, z_min, z_max, steps):
|
|
70 |
roots_found.append(0.5 * (zl + zr))
|
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 |
"""
|
@@ -248,14 +314,20 @@ def compute_custom_expression(betas, z_a, y, s_num_expr, s_denom_expr, is_s_base
|
|
248 |
def generate_z_vs_beta_plot(z_a, y, z_min, z_max, beta_steps, z_steps,
|
249 |
s_num_expr=None, s_denom_expr=None,
|
250 |
z_num_expr=None, z_denom_expr=None,
|
251 |
-
show_derivatives=False):
|
252 |
if z_a <= 0 or y <= 0 or z_min >= z_max:
|
253 |
st.error("Invalid input parameters.")
|
254 |
return None
|
255 |
|
256 |
-
|
257 |
-
|
258 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
259 |
high_y_curve = compute_high_y_curve(betas, z_a, y)
|
260 |
alt_low_expr = compute_alternate_low_expr(betas, z_a, y)
|
261 |
|
@@ -282,10 +354,11 @@ def generate_z_vs_beta_plot(z_a, y, z_min, z_max, beta_steps, z_steps,
|
|
282 |
fig = go.Figure()
|
283 |
|
284 |
# Original curves
|
|
|
285 |
fig.add_trace(go.Scatter(x=betas, y=z_maxs, mode="markers+lines",
|
286 |
-
name="Upper z*(β)", line=dict(color='blue')))
|
287 |
fig.add_trace(go.Scatter(x=betas, y=z_mins, mode="markers+lines",
|
288 |
-
name="Lower z*(β)", line=dict(color='blue')))
|
289 |
# Removed the Low y Expression trace
|
290 |
fig.add_trace(go.Scatter(x=betas, y=high_y_curve, mode="markers+lines",
|
291 |
name="High y Expression", line=dict(color='green')))
|
@@ -296,7 +369,7 @@ def generate_z_vs_beta_plot(z_a, y, z_min, z_max, beta_steps, z_steps,
|
|
296 |
fig.add_trace(go.Scatter(x=betas, y=max_k_curve, mode="lines",
|
297 |
name="Max k Expression", line=dict(color='red', width=2)))
|
298 |
fig.add_trace(go.Scatter(x=betas, y=min_t_curve, mode="lines",
|
299 |
-
name="Min t Expression", line=dict(color='
|
300 |
|
301 |
if custom_curve1 is not None:
|
302 |
fig.add_trace(go.Scatter(x=betas, y=custom_curve1, mode="markers+lines",
|
@@ -336,8 +409,9 @@ def generate_z_vs_beta_plot(z_a, y, z_min, z_max, beta_steps, z_steps,
|
|
336 |
fig.add_trace(go.Scatter(x=betas, y=min_t_derivatives[1], mode="lines",
|
337 |
name="Min t d²/dβ²", line=dict(color='orange', dash='dot')))
|
338 |
|
|
|
339 |
fig.update_layout(
|
340 |
-
title="Curves vs β: z*(β) Boundaries and Asymptotic Expressions",
|
341 |
xaxis_title="β",
|
342 |
yaxis_title="Value",
|
343 |
hovermode="x unified",
|
@@ -481,6 +555,9 @@ with tab1:
|
|
481 |
beta_steps = st.slider("β steps", min_value=51, max_value=501, value=201, step=50, key="beta_steps")
|
482 |
z_steps = st.slider("z grid steps", min_value=1000, max_value=100000, value=50000, step=1000, key="z_steps")
|
483 |
|
|
|
|
|
|
|
484 |
st.subheader("Custom Expression 1 (s-based)")
|
485 |
st.markdown("""Enter expressions for s = numerator/denominator
|
486 |
(using variables `y`, `beta`, `z_a`, and `sqrt()`)""")
|
@@ -500,17 +577,18 @@ with tab1:
|
|
500 |
if st.button("Compute z vs. β Curves", key="tab1_button"):
|
501 |
with col2:
|
502 |
fig = generate_z_vs_beta_plot(z_a_1, y_1, z_min_1, z_max_1, beta_steps, z_steps,
|
503 |
-
s_num, s_denom, z_num, z_denom, show_derivatives)
|
504 |
if fig is not None:
|
505 |
st.plotly_chart(fig, use_container_width=True)
|
506 |
-
|
507 |
-
st.markdown(""
|
508 |
-
|
509 |
-
- **
|
|
|
510 |
- **High y Expression** (Green): Asymptotic approximation for high y values
|
511 |
-
- **Low Expression** (
|
512 |
- **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)}$
|
513 |
-
- **Min t Expression** (
|
514 |
- **Custom Expression 1** (Purple): Result from user-defined s substituted into the main formula
|
515 |
- **Custom Expression 2** (Magenta): Direct z(β) expression
|
516 |
""")
|
@@ -577,6 +655,9 @@ with tab3:
|
|
577 |
beta_steps_diff = st.slider("β steps", min_value=51, max_value=501, value=201, step=50, key="beta_steps_diff")
|
578 |
z_steps_diff = st.slider("z grid steps", min_value=1000, max_value=100000, value=50000, step=1000, key="z_steps_diff")
|
579 |
|
|
|
|
|
|
|
580 |
# Add options for curve selection
|
581 |
st.subheader("Curves to Analyze")
|
582 |
analyze_upper_lower = st.checkbox("Upper-Lower Difference", value=True)
|
@@ -585,7 +666,11 @@ with tab3:
|
|
585 |
|
586 |
if st.button("Compute Differentials", key="tab3_button"):
|
587 |
with col2:
|
588 |
-
|
|
|
|
|
|
|
|
|
589 |
|
590 |
# Create figure
|
591 |
fig_diff = go.Figure()
|
@@ -595,12 +680,13 @@ with tab3:
|
|
595 |
d1 = np.gradient(diff_curve, betas_diff)
|
596 |
d2 = np.gradient(d1, betas_diff)
|
597 |
|
|
|
598 |
fig_diff.add_trace(go.Scatter(x=betas_diff, y=diff_curve, mode="lines",
|
599 |
-
name="Upper-Lower Difference", line=dict(color="magenta", width=2)))
|
600 |
fig_diff.add_trace(go.Scatter(x=betas_diff, y=d1, mode="lines",
|
601 |
-
name="Upper-Lower d/dβ", line=dict(color="magenta", dash='dash')))
|
602 |
fig_diff.add_trace(go.Scatter(x=betas_diff, y=d2, mode="lines",
|
603 |
-
name="Upper-Lower d²/dβ²", line=dict(color="magenta", dash='dot')))
|
604 |
|
605 |
if analyze_high_y:
|
606 |
high_y_curve = compute_high_y_curve(betas_diff, z_a_diff, y_diff)
|
@@ -626,8 +712,9 @@ with tab3:
|
|
626 |
fig_diff.add_trace(go.Scatter(x=betas_diff, y=d2, mode="lines",
|
627 |
name="Alt Low d²/dβ²", line=dict(color="orange", dash='dot')))
|
628 |
|
|
|
629 |
fig_diff.update_layout(
|
630 |
-
title="Differential Analysis vs. β",
|
631 |
xaxis_title="β",
|
632 |
yaxis_title="Value",
|
633 |
hovermode="x unified",
|
|
|
70 |
roots_found.append(0.5 * (zl + zr))
|
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
|
111 |
+
p = int(y * n)
|
112 |
+
|
113 |
+
# Constructing T_n (Population / Shape Matrix)
|
114 |
+
T_diag = np.where(np.random.rand(p) < beta, z_a, 1.0)
|
115 |
+
T_n = np.diag(T_diag)
|
116 |
+
|
117 |
+
# Generate the data matrix X with i.i.d. standard normal entries
|
118 |
+
X = np.random.randn(p, n)
|
119 |
+
|
120 |
+
# Compute the sample covariance matrix S_n = (1/n) * XX^T
|
121 |
+
S_n = (1 / n) * (X @ X.T)
|
122 |
+
|
123 |
+
# Compute B_n = S_n T_n
|
124 |
+
B_n = S_n @ T_n
|
125 |
+
|
126 |
+
# Compute eigenvalues of B_n
|
127 |
+
eigenvalues = np.linalg.eigvalsh(B_n)
|
128 |
+
|
129 |
+
# Find minimum and maximum eigenvalues
|
130 |
+
min_vals.append(np.min(eigenvalues))
|
131 |
+
max_vals.append(np.max(eigenvalues))
|
132 |
+
|
133 |
+
# Average over seeds for stability
|
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 |
"""
|
|
|
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 |
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')))
|
|
|
369 |
fig.add_trace(go.Scatter(x=betas, y=max_k_curve, mode="lines",
|
370 |
name="Max k Expression", line=dict(color='red', width=2)))
|
371 |
fig.add_trace(go.Scatter(x=betas, y=min_t_curve, mode="lines",
|
372 |
+
name="Min t Expression", line=dict(color='orange', width=2)))
|
373 |
|
374 |
if custom_curve1 is not None:
|
375 |
fig.add_trace(go.Scatter(x=betas, y=custom_curve1, mode="markers+lines",
|
|
|
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",
|
|
|
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
|
563 |
(using variables `y`, `beta`, `z_a`, and `sqrt()`)""")
|
|
|
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(f"""
|
586 |
+
- **Upper z*(β)** (Blue): Maximum z value where roots transition between real and complex ({method_used})
|
587 |
+
- **Lower z*(β)** (Light Blue): Minimum z value where roots transition between real and complex ({method_used})
|
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 |
""")
|
|
|
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")
|
663 |
analyze_upper_lower = st.checkbox("Upper-Lower Difference", value=True)
|
|
|
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 |
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 |
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",
|