Spaces:
Running
Running
Update app.py
Browse files
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
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 |
-
|
97 |
-
|
98 |
-
max_eigenvalues = np.zeros_like(betas)
|
99 |
|
100 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 |
-
|
138 |
-
|
139 |
-
|
140 |
-
|
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,
|
|
|
|
|
|
|
318 |
if z_a <= 0 or y <= 0 or z_min >= z_max:
|
319 |
st.error("Invalid input parameters.")
|
320 |
return None
|
321 |
|
322 |
-
|
|
|
323 |
if use_eigenvalue_method:
|
324 |
-
# Use
|
325 |
-
|
|
|
|
|
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 |
-
|
358 |
-
|
359 |
-
|
360 |
-
|
361 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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=
|
|
|
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
|
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 |
-
|
559 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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
|
578 |
with col2:
|
579 |
-
|
580 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
581 |
if fig is not None:
|
582 |
st.plotly_chart(fig, use_container_width=True)
|
583 |
-
|
584 |
-
|
585 |
-
|
586 |
-
|
587 |
-
|
588 |
-
|
589 |
-
|
590 |
-
|
591 |
-
|
592 |
-
|
593 |
-
|
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 |
-
|
659 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 |
-
|
670 |
-
|
671 |
-
|
|
|
|
|
|
|
|
|
672 |
else:
|
673 |
-
betas_diff, lower_vals, upper_vals = sweep_beta_and_find_z_bounds(
|
|
|
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"
|
686 |
fig_diff.add_trace(go.Scatter(x=betas_diff, y=d1, mode="lines",
|
687 |
-
name="Upper-Lower d/dβ"
|
688 |
fig_diff.add_trace(go.Scatter(x=betas_diff, y=d2, mode="lines",
|
689 |
-
name="Upper-Lower d²/dβ²"
|
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=
|
|
|
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",
|