euler314 commited on
Commit
913575d
·
verified ·
1 Parent(s): da34afc

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +14 -45
app.py CHANGED
@@ -8,7 +8,7 @@ from scipy.optimize import fsolve
8
  st.set_page_config(
9
  page_title="Cubic Root Analysis",
10
  layout="wide",
11
- initial_sidebar_state="expanded" # Changed to expanded
12
  )
13
 
14
  # Move custom expression inputs to sidebar
@@ -28,6 +28,7 @@ with st.sidebar:
28
 
29
  custom_num_expr = st.text_input("Numerator Expression", value=default_num)
30
  custom_denom_expr = st.text_input("Denominator Expression", value=default_denom)
 
31
  #############################
32
  # 1) Define the discriminant
33
  #############################
@@ -37,7 +38,7 @@ z_sym, beta_sym, z_a_sym, y_sym = sp.symbols("z beta z_a y", real=True, positive
37
 
38
  # Define a, b, c, d in terms of z_sym, beta_sym, z_a_sym, y_sym
39
  a_sym = z_sym * z_a_sym
40
- b_sym = z_sym * z_a_sym + z_sym + z_a_sym - z_a_sym*y_sym # Fixed coefficient b
41
  c_sym = z_sym + z_a_sym + 1 - y_sym*(beta_sym*z_a_sym + 1 - beta_sym)
42
  d_sym = 1
43
 
@@ -52,10 +53,6 @@ discriminant_func = sp.lambdify((z_sym, beta_sym, z_a_sym, y_sym), Delta_expr, "
52
 
53
  @st.cache_data
54
  def find_z_at_discriminant_zero(z_a, y, beta, z_min, z_max, steps):
55
- """
56
- Numerically scan z in [z_min, z_max] looking for sign changes of
57
- Delta(z) = 0. Returns all roots found via bisection.
58
- """
59
  z_grid = np.linspace(z_min, z_max, steps)
60
  disc_vals = discriminant_func(z_grid, beta, z_a, y)
61
 
@@ -90,12 +87,9 @@ def find_z_at_discriminant_zero(z_a, y, beta, z_min, z_max, steps):
90
  roots_found.append(root_approx)
91
 
92
  return np.array(roots_found)
 
93
  @st.cache_data
94
  def sweep_beta_and_find_z_bounds(z_a, y, z_min, z_max, beta_steps, z_steps):
95
- """
96
- For each beta, find both the largest and smallest z where discriminant=0.
97
- Returns (betas, z_min_values, z_max_values).
98
- """
99
  betas = np.linspace(0, 1, beta_steps)
100
  z_min_values = []
101
  z_max_values = []
@@ -113,9 +107,6 @@ def sweep_beta_and_find_z_bounds(z_a, y, z_min, z_max, beta_steps, z_steps):
113
 
114
  @st.cache_data
115
  def compute_low_y_curve(betas, z_a, y):
116
- """
117
- Compute the additional curve with proper handling of divide by zero cases
118
- """
119
  betas = np.array(betas)
120
  with np.errstate(invalid='ignore', divide='ignore'):
121
  sqrt_term = y * betas * (z_a - 1)
@@ -124,16 +115,12 @@ def compute_low_y_curve(betas, z_a, y):
124
  term = (-1 + sqrt_term)/z_a
125
  numerator = (y - 2)*term + y * betas * ((z_a - 1)/z_a) - 1/z_a - 1
126
  denominator = term**2 + term
127
- # Handle division by zero and invalid values
128
  mask = (denominator != 0) & ~np.isnan(denominator) & ~np.isnan(numerator)
129
  return np.where(mask, numerator/denominator, np.nan)
130
 
131
  @st.cache_data
132
  def compute_high_y_curve(betas, z_a, y):
133
- """
134
- Compute the expression: (-4a(a-1)yβ - 2ay + 2a(2a-1))/(1-2a)
135
- """
136
- a = z_a # for clarity in the formula
137
  betas = np.array(betas)
138
  denominator = 1 - 2*a
139
 
@@ -145,28 +132,15 @@ def compute_high_y_curve(betas, z_a, y):
145
 
146
  @st.cache_data
147
  def compute_z_difference_and_derivatives(z_a, y, z_min, z_max, beta_steps, z_steps):
148
- """
149
- Compute the difference between upper and lower z*(β) curves and their derivatives
150
- """
151
  betas, z_mins, z_maxs = sweep_beta_and_find_z_bounds(z_a, y, z_min, z_max, beta_steps, z_steps)
152
 
153
- # Compute difference
154
  z_difference = z_maxs - z_mins
155
-
156
- # First derivatives
157
  dz_diff_dbeta = np.gradient(z_difference, betas)
158
-
159
- # Second derivatives
160
  d2z_diff_dbeta2 = np.gradient(dz_diff_dbeta, betas)
161
 
162
  return betas, z_difference, dz_diff_dbeta, d2z_diff_dbeta2
 
163
  def compute_custom_expression(betas, z_a, y, num_expr_str, denom_expr_str):
164
- """
165
- Compute a custom curve given numerator and denominator expressions
166
- as strings that can depend on z_a, beta, and y.
167
- Allows 'a' as an alias for z_a.
168
- """
169
- # Define allowed symbols. Also allow 'a' as an alias for z_a.
170
  beta_sym, z_a_sym, y_sym, a_sym = sp.symbols("beta z_a y a", positive=True)
171
  local_dict = {"beta": beta_sym, "z_a": z_a_sym, "y": y_sym, "a": z_a_sym}
172
 
@@ -191,7 +165,6 @@ def generate_z_vs_beta_plot(z_a, y, z_min, z_max, beta_steps, z_steps,
191
  return None, None
192
 
193
  betas = np.linspace(0, 1, beta_steps)
194
-
195
  betas, z_mins, z_maxs = sweep_beta_and_find_z_bounds(z_a, y, z_min, z_max, beta_steps, z_steps)
196
  low_y_curve = compute_low_y_curve(betas, z_a, y)
197
  high_y_curve = compute_high_y_curve(betas, z_a, y)
@@ -219,7 +192,8 @@ def generate_z_vs_beta_plot(z_a, y, z_min, z_max, beta_steps, z_steps,
219
  line=dict(color='lightblue'),
220
  )
221
  )
222
- fig.add_trace(
 
223
  go.Scatter(
224
  x=betas,
225
  y=low_y_curve,
@@ -242,7 +216,6 @@ fig.add_trace(
242
  )
243
 
244
  custom_curve = None
245
- # Add custom expression if both numerator and denominator are provided
246
  if custom_num_expr and custom_denom_expr:
247
  custom_curve = compute_custom_expression(betas, z_a, y, custom_num_expr, custom_denom_expr)
248
  fig.add_trace(
@@ -263,7 +236,6 @@ fig.add_trace(
263
  hovermode="x unified",
264
  )
265
 
266
- # Compute Derivatives with Respect to β
267
  dzmax_dbeta = np.gradient(z_maxs, betas)
268
  dzmin_dbeta = np.gradient(z_mins, betas)
269
  dlowy_dbeta = np.gradient(low_y_curve, betas)
@@ -282,7 +254,8 @@ fig.add_trace(
282
  line=dict(color='blue'),
283
  )
284
  )
285
- fig_deriv.add_trace(
 
286
  go.Scatter(
287
  x=betas,
288
  y=dzmin_dbeta,
@@ -337,9 +310,6 @@ fig_deriv.add_trace(
337
  return fig, fig_deriv
338
 
339
  def compute_cubic_roots(z, beta, z_a, y):
340
- """
341
- Compute the roots of the cubic equation for given parameters.
342
- """
343
  a = z * z_a
344
  b = z * z_a + z + z_a - z_a*y
345
  c = z + z_a + 1 - y*(beta*z_a + 1 - beta)
@@ -348,8 +318,8 @@ def compute_cubic_roots(z, beta, z_a, y):
348
  coeffs = [a, b, c, d]
349
  roots = np.roots(coeffs)
350
  return roots
 
351
  def generate_root_plots(beta, y, z_a, z_min, z_max, n_points):
352
- """Generate both Im(s) and Re(s) vs. z plots"""
353
  if z_a <= 0 or y <= 0 or z_min >= z_max:
354
  st.error("Invalid input parameters.")
355
  return None, None
@@ -367,7 +337,6 @@ def generate_root_plots(beta, y, z_a, z_min, z_max, n_points):
367
  ims = np.array(ims)
368
  res = np.array(res)
369
 
370
- # Create Im(s) plot
371
  fig_im = go.Figure()
372
  for i in range(3):
373
  fig_im.add_trace(
@@ -386,7 +355,6 @@ def generate_root_plots(beta, y, z_a, z_min, z_max, n_points):
386
  hovermode="x unified",
387
  )
388
 
389
- # Create Re(s) plot
390
  fig_re = go.Figure()
391
  for i in range(3):
392
  fig_re.add_trace(
@@ -406,11 +374,12 @@ def generate_root_plots(beta, y, z_a, z_min, z_max, n_points):
406
  )
407
 
408
  return fig_im, fig_re
 
409
  # ------------------- Streamlit UI -------------------
410
 
411
  st.title("Cubic Root Analysis")
412
 
413
- tab1, tab2, tab3, tab4 = st.tabs(["z*(β) Curves", "Im{s} vs. z", "Curve Intersections", "z*(β) Difference Analysis"])
414
 
415
  with tab1:
416
  st.header("Find z Values where Cubic Roots Transition Between Real and Complex")
@@ -458,7 +427,7 @@ with tab2:
458
  st.plotly_chart(fig_im, use_container_width=True)
459
  st.plotly_chart(fig_re, use_container_width=True)
460
 
461
- with tab4:
462
  st.header("z*(β) Difference Analysis")
463
 
464
  col1, col2 = st.columns([1, 2])
 
8
  st.set_page_config(
9
  page_title="Cubic Root Analysis",
10
  layout="wide",
11
+ initial_sidebar_state="expanded"
12
  )
13
 
14
  # Move custom expression inputs to sidebar
 
28
 
29
  custom_num_expr = st.text_input("Numerator Expression", value=default_num)
30
  custom_denom_expr = st.text_input("Denominator Expression", value=default_denom)
31
+
32
  #############################
33
  # 1) Define the discriminant
34
  #############################
 
38
 
39
  # Define a, b, c, d in terms of z_sym, beta_sym, z_a_sym, y_sym
40
  a_sym = z_sym * z_a_sym
41
+ b_sym = z_sym * z_a_sym + z_sym + z_a_sym - z_a_sym*y_sym
42
  c_sym = z_sym + z_a_sym + 1 - y_sym*(beta_sym*z_a_sym + 1 - beta_sym)
43
  d_sym = 1
44
 
 
53
 
54
  @st.cache_data
55
  def find_z_at_discriminant_zero(z_a, y, beta, z_min, z_max, steps):
 
 
 
 
56
  z_grid = np.linspace(z_min, z_max, steps)
57
  disc_vals = discriminant_func(z_grid, beta, z_a, y)
58
 
 
87
  roots_found.append(root_approx)
88
 
89
  return np.array(roots_found)
90
+
91
  @st.cache_data
92
  def sweep_beta_and_find_z_bounds(z_a, y, z_min, z_max, beta_steps, z_steps):
 
 
 
 
93
  betas = np.linspace(0, 1, beta_steps)
94
  z_min_values = []
95
  z_max_values = []
 
107
 
108
  @st.cache_data
109
  def compute_low_y_curve(betas, z_a, y):
 
 
 
110
  betas = np.array(betas)
111
  with np.errstate(invalid='ignore', divide='ignore'):
112
  sqrt_term = y * betas * (z_a - 1)
 
115
  term = (-1 + sqrt_term)/z_a
116
  numerator = (y - 2)*term + y * betas * ((z_a - 1)/z_a) - 1/z_a - 1
117
  denominator = term**2 + term
 
118
  mask = (denominator != 0) & ~np.isnan(denominator) & ~np.isnan(numerator)
119
  return np.where(mask, numerator/denominator, np.nan)
120
 
121
  @st.cache_data
122
  def compute_high_y_curve(betas, z_a, y):
123
+ a = z_a
 
 
 
124
  betas = np.array(betas)
125
  denominator = 1 - 2*a
126
 
 
132
 
133
  @st.cache_data
134
  def compute_z_difference_and_derivatives(z_a, y, z_min, z_max, beta_steps, z_steps):
 
 
 
135
  betas, z_mins, z_maxs = sweep_beta_and_find_z_bounds(z_a, y, z_min, z_max, beta_steps, z_steps)
136
 
 
137
  z_difference = z_maxs - z_mins
 
 
138
  dz_diff_dbeta = np.gradient(z_difference, betas)
 
 
139
  d2z_diff_dbeta2 = np.gradient(dz_diff_dbeta, betas)
140
 
141
  return betas, z_difference, dz_diff_dbeta, d2z_diff_dbeta2
142
+
143
  def compute_custom_expression(betas, z_a, y, num_expr_str, denom_expr_str):
 
 
 
 
 
 
144
  beta_sym, z_a_sym, y_sym, a_sym = sp.symbols("beta z_a y a", positive=True)
145
  local_dict = {"beta": beta_sym, "z_a": z_a_sym, "y": y_sym, "a": z_a_sym}
146
 
 
165
  return None, None
166
 
167
  betas = np.linspace(0, 1, beta_steps)
 
168
  betas, z_mins, z_maxs = sweep_beta_and_find_z_bounds(z_a, y, z_min, z_max, beta_steps, z_steps)
169
  low_y_curve = compute_low_y_curve(betas, z_a, y)
170
  high_y_curve = compute_high_y_curve(betas, z_a, y)
 
192
  line=dict(color='lightblue'),
193
  )
194
  )
195
+
196
+ fig.add_trace(
197
  go.Scatter(
198
  x=betas,
199
  y=low_y_curve,
 
216
  )
217
 
218
  custom_curve = None
 
219
  if custom_num_expr and custom_denom_expr:
220
  custom_curve = compute_custom_expression(betas, z_a, y, custom_num_expr, custom_denom_expr)
221
  fig.add_trace(
 
236
  hovermode="x unified",
237
  )
238
 
 
239
  dzmax_dbeta = np.gradient(z_maxs, betas)
240
  dzmin_dbeta = np.gradient(z_mins, betas)
241
  dlowy_dbeta = np.gradient(low_y_curve, betas)
 
254
  line=dict(color='blue'),
255
  )
256
  )
257
+
258
+ fig_deriv.add_trace(
259
  go.Scatter(
260
  x=betas,
261
  y=dzmin_dbeta,
 
310
  return fig, fig_deriv
311
 
312
  def compute_cubic_roots(z, beta, z_a, y):
 
 
 
313
  a = z * z_a
314
  b = z * z_a + z + z_a - z_a*y
315
  c = z + z_a + 1 - y*(beta*z_a + 1 - beta)
 
318
  coeffs = [a, b, c, d]
319
  roots = np.roots(coeffs)
320
  return roots
321
+
322
  def generate_root_plots(beta, y, z_a, z_min, z_max, n_points):
 
323
  if z_a <= 0 or y <= 0 or z_min >= z_max:
324
  st.error("Invalid input parameters.")
325
  return None, None
 
337
  ims = np.array(ims)
338
  res = np.array(res)
339
 
 
340
  fig_im = go.Figure()
341
  for i in range(3):
342
  fig_im.add_trace(
 
355
  hovermode="x unified",
356
  )
357
 
 
358
  fig_re = go.Figure()
359
  for i in range(3):
360
  fig_re.add_trace(
 
374
  )
375
 
376
  return fig_im, fig_re
377
+
378
  # ------------------- Streamlit UI -------------------
379
 
380
  st.title("Cubic Root Analysis")
381
 
382
+ tab1, tab2, tab3 = st.tabs(["z*(β) Curves", "Im{s} vs. z", "z*(β) Difference Analysis"])
383
 
384
  with tab1:
385
  st.header("Find z Values where Cubic Roots Transition Between Real and Complex")
 
427
  st.plotly_chart(fig_im, use_container_width=True)
428
  st.plotly_chart(fig_re, use_container_width=True)
429
 
430
+ with tab3:
431
  st.header("z*(β) Difference Analysis")
432
 
433
  col1, col2 = st.columns([1, 2])