euler314 commited on
Commit
aceb3e5
·
verified ·
1 Parent(s): 764f20d

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +468 -345
app.py CHANGED
@@ -8,6 +8,8 @@ from PIL import Image
8
  import time
9
  import io
10
  import sys
 
 
11
 
12
  # Set page config with wider layout
13
  st.set_page_config(
@@ -65,6 +67,18 @@ st.markdown("""
65
  padding: 10px;
66
  margin: 10px 0;
67
  }
 
 
 
 
 
 
 
 
 
 
 
 
68
  </style>
69
  """, unsafe_allow_html=True)
70
 
@@ -76,48 +90,14 @@ current_dir = os.getcwd()
76
  output_dir = os.path.join(current_dir, "output")
77
  os.makedirs(output_dir, exist_ok=True)
78
 
79
- # Compile the C++ code at runtime
80
  cpp_file = os.path.join(current_dir, "app.cpp")
81
  executable = os.path.join(current_dir, "eigen_analysis")
82
-
83
- # Check if cpp file exists and compile if necessary
84
- if not os.path.exists(cpp_file):
85
- st.error(f"C++ source file not found at: {cpp_file}")
86
- st.stop()
87
-
88
- # Compile the C++ code with the right OpenCV libraries
89
- if not os.path.exists(executable) or st.sidebar.button("Recompile C++ Code"):
90
- with st.sidebar:
91
- with st.spinner("Compiling C++ code..."):
92
- compile_commands = [
93
- f"g++ -o {executable} {cpp_file} `pkg-config --cflags --libs opencv4` -std=c++11",
94
- f"g++ -o {executable} {cpp_file} `pkg-config --cflags --libs opencv` -std=c++11",
95
- f"g++ -o {executable} {cpp_file} -I/usr/include/opencv4 -lopencv_core -lopencv_imgproc -std=c++11"
96
- ]
97
-
98
- compiled = False
99
- for cmd in compile_commands:
100
- compile_result = subprocess.run(
101
- cmd,
102
- shell=True,
103
- capture_output=True,
104
- text=True
105
- )
106
-
107
- if compile_result.returncode == 0:
108
- compiled = True
109
- break
110
-
111
- if not compiled:
112
- st.error("All compilation attempts failed. Please check the system requirements.")
113
- st.stop()
114
-
115
- # Make sure the executable is executable
116
- os.chmod(executable, 0o755)
117
- st.success("C++ code compiled successfully")
118
 
119
  # Helper function for running commands with better debugging
120
- def run_command(cmd, show_output=True):
121
  cmd_str = " ".join(cmd)
122
  if show_output:
123
  st.code(f"Running command: {cmd_str}", language="bash")
@@ -129,29 +109,91 @@ def run_command(cmd, show_output=True):
129
  stdout=subprocess.PIPE,
130
  stderr=subprocess.PIPE,
131
  text=True,
132
- check=True
 
133
  )
134
 
135
- if show_output:
136
- st.write("Command completed successfully.")
137
- if result.stdout:
138
- st.text("Output:")
139
- st.code(result.stdout)
140
-
141
- return True, result.stdout, result.stderr
142
-
143
- except subprocess.CalledProcessError as e:
144
- if show_output:
145
- st.error(f"Command failed with return code {e.returncode}")
146
- st.error(f"Command: {cmd_str}")
147
- st.error(f"Error output: {e.stderr}")
148
- return False, e.stdout, e.stderr
149
 
 
 
 
 
150
  except Exception as e:
151
  if show_output:
152
  st.error(f"Error executing command: {str(e)}")
153
  return False, "", str(e)
154
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
155
  # Create tabs for different analyses
156
  tab1, tab2 = st.tabs(["Eigenvalue Analysis", "Im(s) vs z Analysis"])
157
 
@@ -212,6 +254,16 @@ with tab1:
212
 
213
  # Debug mode
214
  debug_mode = st.checkbox("Debug Mode", value=False, key="eig_debug")
 
 
 
 
 
 
 
 
 
 
215
 
216
  # Generate button
217
  eig_generate_button = st.button("Generate Eigenvalue Analysis",
@@ -263,34 +315,52 @@ with tab1:
263
  status_text.text("Running eigenvalue analysis...")
264
 
265
  if debug_mode:
266
- success, stdout, stderr = run_command(cmd, True)
 
 
 
267
  else:
268
  # Start the process with pipe for stdout to read progress
269
  process = subprocess.Popen(
270
  cmd,
271
  stdout=subprocess.PIPE,
272
  stderr=subprocess.PIPE,
273
- text=True
 
 
274
  )
275
 
276
  # Track progress from stdout
277
  success = True
 
 
 
278
  while True:
 
 
 
 
 
 
 
 
279
  line = process.stdout.readline()
280
  if not line and process.poll() is not None:
281
  break
282
 
283
- if line.startswith("PROGRESS:"):
284
- try:
285
- # Update progress bar
286
- progress_value = float(line.split(":")[1].strip())
287
- progress_bar.progress(progress_value)
288
- status_text.text(f"Calculating... {int(progress_value * 100)}% complete")
289
- except:
290
- pass
291
- elif line:
292
- status_text.text(line.strip())
293
-
 
 
294
  # Get the return code and stderr
295
  returncode = process.poll()
296
  stderr = process.stderr.read()
@@ -298,6 +368,8 @@ with tab1:
298
  if returncode != 0:
299
  success = False
300
  st.error(f"Error executing the analysis: {stderr}")
 
 
301
 
302
  if success:
303
  progress_bar.progress(1.0)
@@ -308,157 +380,177 @@ with tab1:
308
  st.error(f"Output file not created: {data_file}")
309
  st.stop()
310
 
311
- # Load the results from the JSON file
312
- with open(data_file, 'r') as f:
313
- data = json.load(f)
314
-
315
- # Extract data
316
- beta_values = np.array(data['beta_values'])
317
- max_eigenvalues = np.array(data['max_eigenvalues'])
318
- min_eigenvalues = np.array(data['min_eigenvalues'])
319
- theoretical_max = np.array(data['theoretical_max'])
320
- theoretical_min = np.array(data['theoretical_min'])
321
-
322
- # Create an interactive plot using Plotly
323
- fig = go.Figure()
324
-
325
- # Add traces for each line
326
- fig.add_trace(go.Scatter(
327
- x=beta_values,
328
- y=max_eigenvalues,
329
- mode='lines+markers',
330
- name='Empirical Max Eigenvalue',
331
- line=dict(color='rgb(220, 60, 60)', width=3),
332
- marker=dict(
333
- symbol='circle',
334
- size=8,
335
- color='rgb(220, 60, 60)',
336
- line=dict(color='white', width=1)
337
- ),
338
- hovertemplate='β: %{x:.3f}<br>Value: %{y:.6f}<extra>Empirical Max</extra>'
339
- ))
340
-
341
- fig.add_trace(go.Scatter(
342
- x=beta_values,
343
- y=min_eigenvalues,
344
- mode='lines+markers',
345
- name='Empirical Min Eigenvalue',
346
- line=dict(color='rgb(60, 60, 220)', width=3),
347
- marker=dict(
348
- symbol='circle',
349
- size=8,
350
- color='rgb(60, 60, 220)',
351
- line=dict(color='white', width=1)
352
- ),
353
- hovertemplate='β: %{x:.3f}<br>Value: %{y:.6f}<extra>Empirical Min</extra>'
354
- ))
355
-
356
- fig.add_trace(go.Scatter(
357
- x=beta_values,
358
- y=theoretical_max,
359
- mode='lines+markers',
360
- name='Theoretical Max Function',
361
- line=dict(color='rgb(30, 180, 30)', width=3),
362
- marker=dict(
363
- symbol='diamond',
364
- size=8,
365
- color='rgb(30, 180, 30)',
366
- line=dict(color='white', width=1)
367
- ),
368
- hovertemplate='β: %{x:.3f}<br>Value: %{y:.6f}<extra>Theoretical Max</extra>'
369
- ))
370
-
371
- fig.add_trace(go.Scatter(
372
- x=beta_values,
373
- y=theoretical_min,
374
- mode='lines+markers',
375
- name='Theoretical Min Function',
376
- line=dict(color='rgb(180, 30, 180)', width=3),
377
- marker=dict(
378
- symbol='diamond',
379
- size=8,
380
- color='rgb(180, 30, 180)',
381
- line=dict(color='white', width=1)
382
- ),
383
- hovertemplate='β: %{x:.3f}<br>Value: %{y:.6f}<extra>Theoretical Min</extra>'
384
- ))
385
-
386
- # Configure layout for better appearance
387
- fig.update_layout(
388
- title={
389
- 'text': f'Eigenvalue Analysis: n={n}, p={p}, a={a}, y={y:.4f}',
390
- 'font': {'size': 24, 'color': '#1E88E5'},
391
- 'y': 0.95,
392
- 'x': 0.5,
393
- 'xanchor': 'center',
394
- 'yanchor': 'top'
395
- },
396
- xaxis={
397
- 'title': 'β Parameter',
398
- 'titlefont': {'size': 18, 'color': '#424242'},
399
- 'tickfont': {'size': 14},
400
- 'gridcolor': 'rgba(220, 220, 220, 0.5)',
401
- 'showgrid': True
402
- },
403
- yaxis={
404
- 'title': 'Eigenvalues',
405
- 'titlefont': {'size': 18, 'color': '#424242'},
406
- 'tickfont': {'size': 14},
407
- 'gridcolor': 'rgba(220, 220, 220, 0.5)',
408
- 'showgrid': True
409
- },
410
- plot_bgcolor='rgba(240, 240, 240, 0.8)',
411
- paper_bgcolor='rgba(249, 249, 249, 0.8)',
412
- hovermode='closest',
413
- legend={
414
- 'font': {'size': 14},
415
- 'bgcolor': 'rgba(255, 255, 255, 0.9)',
416
- 'bordercolor': 'rgba(200, 200, 200, 0.5)',
417
- 'borderwidth': 1
418
- },
419
- margin={'l': 60, 'r': 30, 't': 100, 'b': 60},
420
- height=600,
421
- annotations=[
422
- {
423
- 'text': f"Max Function: max{{k ∈ (0,∞)}} [yβ(a-1)k + (ak+1)((y-1)k-1)]/[(ak+1)(k²+k)]",
424
- 'xref': 'paper', 'yref': 'paper',
425
- 'x': 0.02, 'y': 0.02,
426
- 'showarrow': False,
427
- 'font': {'size': 12, 'color': 'rgb(30, 180, 30)'},
428
- 'bgcolor': 'rgba(255, 255, 255, 0.9)',
429
- 'bordercolor': 'rgb(30, 180, 30)',
430
- 'borderwidth': 1,
431
- 'borderpad': 4
432
  },
433
- {
434
- 'text': f"Min Function: min{{t ∈ (-1/a,0)}} [yβ(a-1)t + (at+1)((y-1)t-1)]/[(at+1)(t²+t)]",
435
- 'xref': 'paper', 'yref': 'paper',
436
- 'x': 0.55, 'y': 0.02,
437
- 'showarrow': False,
438
- 'font': {'size': 12, 'color': 'rgb(180, 30, 180)'},
 
 
 
 
 
 
439
  'bgcolor': 'rgba(255, 255, 255, 0.9)',
440
- 'bordercolor': 'rgb(180, 30, 180)',
441
- 'borderwidth': 1,
442
- 'borderpad': 4
443
- }
444
- ]
445
- )
446
-
447
- # Add custom modebar buttons
448
- fig.update_layout(
449
- modebar_add=[
450
- 'drawline', 'drawopenpath', 'drawclosedpath',
451
- 'drawcircle', 'drawrect', 'eraseshape'
452
- ],
453
- modebar_remove=['lasso2d', 'select2d'],
454
- dragmode='zoom'
455
- )
456
-
457
- # Clear progress container
458
- progress_container.empty()
459
-
460
- # Display the interactive plot in Streamlit
461
- st.plotly_chart(fig, use_container_width=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
462
 
463
  except Exception as e:
464
  st.error(f"An error occurred: {str(e)}")
@@ -625,6 +717,16 @@ with tab2:
625
  # Debug mode
626
  cubic_debug_mode = st.checkbox("Debug Mode", value=False, key="cubic_debug")
627
 
 
 
 
 
 
 
 
 
 
 
628
  # Show cubic equation
629
  st.markdown('<div class="math-box">', unsafe_allow_html=True)
630
  st.markdown("### Cubic Equation")
@@ -678,13 +780,12 @@ with tab2:
678
  status_text.text("Calculating Im(s) vs z values...")
679
 
680
  if cubic_debug_mode:
681
- success, stdout, stderr = run_command(cmd, True)
682
  else:
683
  # Run the command with our helper function
684
- result = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
685
- success = result.returncode == 0
686
  if not success:
687
- st.error(f"Error executing cubic analysis: {result.stderr}")
688
 
689
  if success:
690
  status_text.text("Calculations complete! Generating visualization...")
@@ -694,132 +795,140 @@ with tab2:
694
  st.error(f"Output file not created: {data_file}")
695
  st.stop()
696
 
697
- # Load the results from the JSON file
698
- with open(data_file, 'r') as f:
699
- data = json.load(f)
700
-
701
- # Extract data
702
- z_values = np.array(data['z_values'])
703
- ims_values1 = np.array(data['ims_values1'])
704
- ims_values2 = np.array(data['ims_values2'])
705
- ims_values3 = np.array(data['ims_values3'])
706
-
707
- # Create an interactive plot using Plotly
708
- fig = go.Figure()
709
-
710
- # Add traces for each root's imaginary part
711
- fig.add_trace(go.Scatter(
712
- x=z_values,
713
- y=ims_values1,
714
- mode='lines',
715
- name='Im(s₁)',
716
- line=dict(color='rgb(220, 60, 60)', width=3),
717
- hovertemplate='z: %{x:.3f}<br>Im(s₁): %{y:.6f}<extra>Root 1</extra>'
718
- ))
719
-
720
- fig.add_trace(go.Scatter(
721
- x=z_values,
722
- y=ims_values2,
723
- mode='lines',
724
- name='Im(s₂)',
725
- line=dict(color='rgb(60, 60, 220)', width=3),
726
- hovertemplate='z: %{x:.3f}<br>Im(s₂): %{y:.6f}<extra>Root 2</extra>'
727
- ))
728
-
729
- fig.add_trace(go.Scatter(
730
- x=z_values,
731
- y=ims_values3,
732
- mode='lines',
733
- name='Im(s₃)',
734
- line=dict(color='rgb(30, 180, 30)', width=3),
735
- hovertemplate='z: %{x:.3f}<br>Im(s₃): %{y:.6f}<extra>Root 3</extra>'
736
- ))
737
-
738
- # Configure layout for better appearance
739
- fig.update_layout(
740
- title={
741
- 'text': f'Im(s) vs z Analysis: a={cubic_a}, y={cubic_y}, β={cubic_beta}',
742
- 'font': {'size': 24, 'color': '#1E88E5'},
743
- 'y': 0.95,
744
- 'x': 0.5,
745
- 'xanchor': 'center',
746
- 'yanchor': 'top'
747
- },
748
- xaxis={
749
- 'title': 'z (logarithmic scale)',
750
- 'titlefont': {'size': 18, 'color': '#424242'},
751
- 'tickfont': {'size': 14},
752
- 'gridcolor': 'rgba(220, 220, 220, 0.5)',
753
- 'showgrid': True,
754
- 'type': 'log' # Use logarithmic scale for better visualization
755
- },
756
- yaxis={
757
- 'title': 'Im(s)',
758
- 'titlefont': {'size': 18, 'color': '#424242'},
759
- 'tickfont': {'size': 14},
760
- 'gridcolor': 'rgba(220, 220, 220, 0.5)',
761
- 'showgrid': True
762
- },
763
- plot_bgcolor='rgba(240, 240, 240, 0.8)',
764
- paper_bgcolor='rgba(249, 249, 249, 0.8)',
765
- hovermode='closest',
766
- legend={
767
- 'font': {'size': 14},
768
- 'bgcolor': 'rgba(255, 255, 255, 0.9)',
769
- 'bordercolor': 'rgba(200, 200, 200, 0.5)',
770
- 'borderwidth': 1
771
- },
772
- margin={'l': 60, 'r': 30, 't': 100, 'b': 60},
773
- height=600,
774
- annotations=[
775
- {
776
- 'text': f"Cubic Equation: {cubic_a}zs³ + [{cubic_a+1}z+{cubic_a}(1-{cubic_y})]s² + [z+{cubic_a+1}-{cubic_y}-{cubic_y*cubic_beta}({cubic_a-1})]s + 1 = 0",
777
- 'xref': 'paper', 'yref': 'paper',
778
- 'x': 0.5, 'y': 0.02,
779
- 'showarrow': False,
780
- 'font': {'size': 12, 'color': 'black'},
781
  'bgcolor': 'rgba(255, 255, 255, 0.9)',
782
- 'bordercolor': 'rgba(0, 0, 0, 0.5)',
783
- 'borderwidth': 1,
784
- 'borderpad': 4,
785
- 'align': 'center'
786
- }
787
- ]
788
- )
789
-
790
- # Add custom modebar buttons
791
- fig.update_layout(
792
- modebar_add=[
793
- 'drawline', 'drawopenpath', 'drawclosedpath',
794
- 'drawcircle', 'drawrect', 'eraseshape'
795
- ],
796
- modebar_remove=['lasso2d', 'select2d'],
797
- dragmode='zoom'
798
- )
799
-
800
- # Clear progress container
801
- progress_container.empty()
802
-
803
- # Display the interactive plot in Streamlit
804
- st.plotly_chart(fig, use_container_width=True)
805
-
806
- # Add explanation text
807
- st.markdown("""
808
- ### Explanation of the Analysis
809
-
810
- This plot shows the imaginary parts of the three roots (s₁, s₂, s₃) of the cubic equation as a function of z.
811
- The cubic equation being solved is:
812
-
813
- ```
814
- zas³ + [z(a+1)+a(1-y)]s² + [z+(a+1)-y-yβ(a-1)]s + 1 = 0
815
- ```
816
-
817
- Where a, y, and β are parameters you can adjust in the control panel. The imaginary parts of the roots represent
818
- oscillatory behavior in the system.
819
-
820
- - When Im(s) = 0, the root is purely real
821
- - When Im(s) ≠ 0, the root has an oscillatory component
822
- """)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
823
 
824
  except Exception as e:
825
  st.error(f"An error occurred: {str(e)}")
@@ -919,4 +1028,18 @@ with tab2:
919
  # Show placeholder
920
  st.info("👈 Set parameters and click 'Generate Im(s) vs z Analysis' to create a visualization.")
921
 
922
- st.markdown('</div>', unsafe_allow_html=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8
  import time
9
  import io
10
  import sys
11
+ import tempfile
12
+ import platform
13
 
14
  # Set page config with wider layout
15
  st.set_page_config(
 
67
  padding: 10px;
68
  margin: 10px 0;
69
  }
70
+ .stWarning {
71
+ background-color: #fff3cd;
72
+ padding: 10px;
73
+ border-left: 3px solid #ffc107;
74
+ margin: 10px 0;
75
+ }
76
+ .stSuccess {
77
+ background-color: #d4edda;
78
+ padding: 10px;
79
+ border-left: 3px solid #28a745;
80
+ margin: 10px 0;
81
+ }
82
  </style>
83
  """, unsafe_allow_html=True)
84
 
 
90
  output_dir = os.path.join(current_dir, "output")
91
  os.makedirs(output_dir, exist_ok=True)
92
 
93
+ # Path to the C++ source file and executable
94
  cpp_file = os.path.join(current_dir, "app.cpp")
95
  executable = os.path.join(current_dir, "eigen_analysis")
96
+ if platform.system() == "Windows":
97
+ executable += ".exe"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
98
 
99
  # Helper function for running commands with better debugging
100
+ def run_command(cmd, show_output=True, timeout=None):
101
  cmd_str = " ".join(cmd)
102
  if show_output:
103
  st.code(f"Running command: {cmd_str}", language="bash")
 
109
  stdout=subprocess.PIPE,
110
  stderr=subprocess.PIPE,
111
  text=True,
112
+ check=False,
113
+ timeout=timeout
114
  )
115
 
116
+ if result.returncode == 0:
117
+ if show_output:
118
+ st.success("Command completed successfully.")
119
+ if result.stdout and show_output:
120
+ with st.expander("Command Output"):
121
+ st.code(result.stdout)
122
+ return True, result.stdout, result.stderr
123
+ else:
124
+ if show_output:
125
+ st.error(f"Command failed with return code {result.returncode}")
126
+ st.error(f"Command: {cmd_str}")
127
+ st.error(f"Error output: {result.stderr}")
128
+ return False, result.stdout, result.stderr
 
129
 
130
+ except subprocess.TimeoutExpired:
131
+ if show_output:
132
+ st.error(f"Command timed out after {timeout} seconds")
133
+ return False, "", f"Command timed out after {timeout} seconds"
134
  except Exception as e:
135
  if show_output:
136
  st.error(f"Error executing command: {str(e)}")
137
  return False, "", str(e)
138
 
139
+ # Check if C++ source file exists
140
+ if not os.path.exists(cpp_file):
141
+ with open(cpp_file, "w") as f:
142
+ st.warning(f"C++ source file not found at: {cpp_file}")
143
+ st.info("Creating an empty file. Please paste the C++ code into this file and recompile.")
144
+ f.write("// Paste the C++ code here and recompile\n")
145
+
146
+ # Compile the C++ code with the right OpenCV libraries
147
+ st.sidebar.title("Compiler Settings")
148
+ need_compile = not os.path.exists(executable) or st.sidebar.button("Recompile C++ Code")
149
+
150
+ if need_compile:
151
+ with st.sidebar:
152
+ with st.spinner("Compiling C++ code..."):
153
+ # Try to detect the OpenCV installation
154
+ opencv_detection_cmd = ["pkg-config", "--cflags", "--libs", "opencv4"]
155
+ opencv_found, opencv_flags, _ = run_command(opencv_detection_cmd, show_output=False)
156
+
157
+ compile_commands = []
158
+
159
+ if opencv_found:
160
+ compile_commands.append(
161
+ f"g++ -o {executable} {cpp_file} {opencv_flags.strip()} -std=c++11"
162
+ )
163
+ else:
164
+ # Try different OpenCV configurations
165
+ compile_commands = [
166
+ f"g++ -o {executable} {cpp_file} `pkg-config --cflags --libs opencv4` -std=c++11",
167
+ f"g++ -o {executable} {cpp_file} `pkg-config --cflags --libs opencv` -std=c++11",
168
+ f"g++ -o {executable} {cpp_file} -I/usr/include/opencv4 -lopencv_core -lopencv_imgproc -std=c++11",
169
+ f"g++ -o {executable} {cpp_file} -I/usr/local/include/opencv4 -lopencv_core -lopencv_imgproc -std=c++11"
170
+ ]
171
+
172
+ compiled = False
173
+ compile_output = ""
174
+
175
+ for cmd in compile_commands:
176
+ st.text(f"Trying: {cmd}")
177
+ success, stdout, stderr = run_command(cmd.split(), show_output=False)
178
+ compile_output += f"Command: {cmd}\nOutput: {stdout}\nError: {stderr}\n\n"
179
+
180
+ if success:
181
+ compiled = True
182
+ st.success(f"Successfully compiled with: {cmd}")
183
+ break
184
+
185
+ if not compiled:
186
+ st.error("All compilation attempts failed.")
187
+ with st.expander("Compilation Details"):
188
+ st.code(compile_output)
189
+ st.stop()
190
+
191
+ # Make sure the executable is executable
192
+ if platform.system() != "Windows":
193
+ os.chmod(executable, 0o755)
194
+
195
+ st.success("C++ code compiled successfully!")
196
+
197
  # Create tabs for different analyses
198
  tab1, tab2 = st.tabs(["Eigenvalue Analysis", "Im(s) vs z Analysis"])
199
 
 
254
 
255
  # Debug mode
256
  debug_mode = st.checkbox("Debug Mode", value=False, key="eig_debug")
257
+
258
+ # Timeout setting
259
+ timeout_seconds = st.number_input(
260
+ "Computation timeout (seconds)",
261
+ min_value=30,
262
+ max_value=3600,
263
+ value=300,
264
+ help="Maximum time allowed for computation before timeout",
265
+ key="eig_timeout"
266
+ )
267
 
268
  # Generate button
269
  eig_generate_button = st.button("Generate Eigenvalue Analysis",
 
315
  status_text.text("Running eigenvalue analysis...")
316
 
317
  if debug_mode:
318
+ success, stdout, stderr = run_command(cmd, True, timeout=timeout_seconds)
319
+ # Process stdout for progress updates
320
+ if success:
321
+ progress_bar.progress(1.0)
322
  else:
323
  # Start the process with pipe for stdout to read progress
324
  process = subprocess.Popen(
325
  cmd,
326
  stdout=subprocess.PIPE,
327
  stderr=subprocess.PIPE,
328
+ text=True,
329
+ bufsize=1,
330
+ universal_newlines=True
331
  )
332
 
333
  # Track progress from stdout
334
  success = True
335
+ stdout_lines = []
336
+
337
+ start_time = time.time()
338
  while True:
339
+ # Check for timeout
340
+ if time.time() - start_time > timeout_seconds:
341
+ process.kill()
342
+ status_text.error(f"Computation timed out after {timeout_seconds} seconds")
343
+ success = False
344
+ break
345
+
346
+ # Try to read a line (non-blocking)
347
  line = process.stdout.readline()
348
  if not line and process.poll() is not None:
349
  break
350
 
351
+ if line:
352
+ stdout_lines.append(line)
353
+ if line.startswith("PROGRESS:"):
354
+ try:
355
+ # Update progress bar
356
+ progress_value = float(line.split(":")[1].strip())
357
+ progress_bar.progress(progress_value)
358
+ status_text.text(f"Calculating... {int(progress_value * 100)}% complete")
359
+ except:
360
+ pass
361
+ elif line:
362
+ status_text.text(line.strip())
363
+
364
  # Get the return code and stderr
365
  returncode = process.poll()
366
  stderr = process.stderr.read()
 
368
  if returncode != 0:
369
  success = False
370
  st.error(f"Error executing the analysis: {stderr}")
371
+ with st.expander("Error Details"):
372
+ st.code(stderr)
373
 
374
  if success:
375
  progress_bar.progress(1.0)
 
380
  st.error(f"Output file not created: {data_file}")
381
  st.stop()
382
 
383
+ try:
384
+ # Load the results from the JSON file
385
+ with open(data_file, 'r') as f:
386
+ data = json.load(f)
387
+
388
+ # Extract data
389
+ beta_values = np.array(data['beta_values'])
390
+ max_eigenvalues = np.array(data['max_eigenvalues'])
391
+ min_eigenvalues = np.array(data['min_eigenvalues'])
392
+ theoretical_max = np.array(data['theoretical_max'])
393
+ theoretical_min = np.array(data['theoretical_min'])
394
+
395
+ # Create an interactive plot using Plotly
396
+ fig = go.Figure()
397
+
398
+ # Add traces for each line
399
+ fig.add_trace(go.Scatter(
400
+ x=beta_values,
401
+ y=max_eigenvalues,
402
+ mode='lines+markers',
403
+ name='Empirical Max Eigenvalue',
404
+ line=dict(color='rgb(220, 60, 60)', width=3),
405
+ marker=dict(
406
+ symbol='circle',
407
+ size=8,
408
+ color='rgb(220, 60, 60)',
409
+ line=dict(color='white', width=1)
410
+ ),
411
+ hovertemplate='β: %{x:.3f}<br>Value: %{y:.6f}<extra>Empirical Max</extra>'
412
+ ))
413
+
414
+ fig.add_trace(go.Scatter(
415
+ x=beta_values,
416
+ y=min_eigenvalues,
417
+ mode='lines+markers',
418
+ name='Empirical Min Eigenvalue',
419
+ line=dict(color='rgb(60, 60, 220)', width=3),
420
+ marker=dict(
421
+ symbol='circle',
422
+ size=8,
423
+ color='rgb(60, 60, 220)',
424
+ line=dict(color='white', width=1)
425
+ ),
426
+ hovertemplate='β: %{x:.3f}<br>Value: %{y:.6f}<extra>Empirical Min</extra>'
427
+ ))
428
+
429
+ fig.add_trace(go.Scatter(
430
+ x=beta_values,
431
+ y=theoretical_max,
432
+ mode='lines+markers',
433
+ name='Theoretical Max Function',
434
+ line=dict(color='rgb(30, 180, 30)', width=3),
435
+ marker=dict(
436
+ symbol='diamond',
437
+ size=8,
438
+ color='rgb(30, 180, 30)',
439
+ line=dict(color='white', width=1)
440
+ ),
441
+ hovertemplate='β: %{x:.3f}<br>Value: %{y:.6f}<extra>Theoretical Max</extra>'
442
+ ))
443
+
444
+ fig.add_trace(go.Scatter(
445
+ x=beta_values,
446
+ y=theoretical_min,
447
+ mode='lines+markers',
448
+ name='Theoretical Min Function',
449
+ line=dict(color='rgb(180, 30, 180)', width=3),
450
+ marker=dict(
451
+ symbol='diamond',
452
+ size=8,
453
+ color='rgb(180, 30, 180)',
454
+ line=dict(color='white', width=1)
455
+ ),
456
+ hovertemplate='β: %{x:.3f}<br>Value: %{y:.6f}<extra>Theoretical Min</extra>'
457
+ ))
458
+
459
+ # Configure layout for better appearance
460
+ fig.update_layout(
461
+ title={
462
+ 'text': f'Eigenvalue Analysis: n={n}, p={p}, a={a}, y={y:.4f}',
463
+ 'font': {'size': 24, 'color': '#1E88E5'},
464
+ 'y': 0.95,
465
+ 'x': 0.5,
466
+ 'xanchor': 'center',
467
+ 'yanchor': 'top'
468
+ },
469
+ xaxis={
470
+ 'title': 'β Parameter',
471
+ 'titlefont': {'size': 18, 'color': '#424242'},
472
+ 'tickfont': {'size': 14},
473
+ 'gridcolor': 'rgba(220, 220, 220, 0.5)',
474
+ 'showgrid': True
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
475
  },
476
+ yaxis={
477
+ 'title': 'Eigenvalues',
478
+ 'titlefont': {'size': 18, 'color': '#424242'},
479
+ 'tickfont': {'size': 14},
480
+ 'gridcolor': 'rgba(220, 220, 220, 0.5)',
481
+ 'showgrid': True
482
+ },
483
+ plot_bgcolor='rgba(240, 240, 240, 0.8)',
484
+ paper_bgcolor='rgba(249, 249, 249, 0.8)',
485
+ hovermode='closest',
486
+ legend={
487
+ 'font': {'size': 14},
488
  'bgcolor': 'rgba(255, 255, 255, 0.9)',
489
+ 'bordercolor': 'rgba(200, 200, 200, 0.5)',
490
+ 'borderwidth': 1
491
+ },
492
+ margin={'l': 60, 'r': 30, 't': 100, 'b': 60},
493
+ height=600,
494
+ annotations=[
495
+ {
496
+ 'text': f"Max Function: max{{k ∈ (0,∞)}} [yβ(a-1)k + (ak+1)((y-1)k-1)]/[(ak+1)(k²+k)]",
497
+ 'xref': 'paper', 'yref': 'paper',
498
+ 'x': 0.02, 'y': 0.02,
499
+ 'showarrow': False,
500
+ 'font': {'size': 12, 'color': 'rgb(30, 180, 30)'},
501
+ 'bgcolor': 'rgba(255, 255, 255, 0.9)',
502
+ 'bordercolor': 'rgb(30, 180, 30)',
503
+ 'borderwidth': 1,
504
+ 'borderpad': 4
505
+ },
506
+ {
507
+ 'text': f"Min Function: min{{t ∈ (-1/a,0)}} [yβ(a-1)t + (at+1)((y-1)t-1)]/[(at+1)(t²+t)]",
508
+ 'xref': 'paper', 'yref': 'paper',
509
+ 'x': 0.55, 'y': 0.02,
510
+ 'showarrow': False,
511
+ 'font': {'size': 12, 'color': 'rgb(180, 30, 180)'},
512
+ 'bgcolor': 'rgba(255, 255, 255, 0.9)',
513
+ 'bordercolor': 'rgb(180, 30, 180)',
514
+ 'borderwidth': 1,
515
+ 'borderpad': 4
516
+ }
517
+ ]
518
+ )
519
+
520
+ # Add custom modebar buttons
521
+ fig.update_layout(
522
+ modebar_add=[
523
+ 'drawline', 'drawopenpath', 'drawclosedpath',
524
+ 'drawcircle', 'drawrect', 'eraseshape'
525
+ ],
526
+ modebar_remove=['lasso2d', 'select2d'],
527
+ dragmode='zoom'
528
+ )
529
+
530
+ # Clear progress container
531
+ progress_container.empty()
532
+
533
+ # Display the interactive plot in Streamlit
534
+ st.plotly_chart(fig, use_container_width=True)
535
+
536
+ # Display statistics
537
+ with st.expander("Statistics"):
538
+ col1, col2 = st.columns(2)
539
+ with col1:
540
+ st.write("### Eigenvalue Statistics")
541
+ st.write(f"Max empirical value: {max_eigenvalues.max():.6f}")
542
+ st.write(f"Min empirical value: {min_eigenvalues.min():.6f}")
543
+ with col2:
544
+ st.write("### Theoretical Values")
545
+ st.write(f"Max theoretical value: {theoretical_max.max():.6f}")
546
+ st.write(f"Min theoretical value: {theoretical_min.min():.6f}")
547
+
548
+ except json.JSONDecodeError as e:
549
+ st.error(f"Error parsing JSON results: {str(e)}")
550
+ if os.path.exists(data_file):
551
+ with open(data_file, 'r') as f:
552
+ content = f.read()
553
+ st.code(content[:1000] + "..." if len(content) > 1000 else content)
554
 
555
  except Exception as e:
556
  st.error(f"An error occurred: {str(e)}")
 
717
  # Debug mode
718
  cubic_debug_mode = st.checkbox("Debug Mode", value=False, key="cubic_debug")
719
 
720
+ # Timeout setting
721
+ cubic_timeout = st.number_input(
722
+ "Computation timeout (seconds)",
723
+ min_value=10,
724
+ max_value=600,
725
+ value=60,
726
+ help="Maximum time allowed for computation before timeout",
727
+ key="cubic_timeout"
728
+ )
729
+
730
  # Show cubic equation
731
  st.markdown('<div class="math-box">', unsafe_allow_html=True)
732
  st.markdown("### Cubic Equation")
 
780
  status_text.text("Calculating Im(s) vs z values...")
781
 
782
  if cubic_debug_mode:
783
+ success, stdout, stderr = run_command(cmd, True, timeout=cubic_timeout)
784
  else:
785
  # Run the command with our helper function
786
+ success, stdout, stderr = run_command(cmd, False, timeout=cubic_timeout)
 
787
  if not success:
788
+ st.error(f"Error executing cubic analysis: {stderr}")
789
 
790
  if success:
791
  status_text.text("Calculations complete! Generating visualization...")
 
795
  st.error(f"Output file not created: {data_file}")
796
  st.stop()
797
 
798
+ try:
799
+ # Load the results from the JSON file
800
+ with open(data_file, 'r') as f:
801
+ data = json.load(f)
802
+
803
+ # Extract data
804
+ z_values = np.array(data['z_values'])
805
+ ims_values1 = np.array(data['ims_values1'])
806
+ ims_values2 = np.array(data['ims_values2'])
807
+ ims_values3 = np.array(data['ims_values3'])
808
+
809
+ # Create an interactive plot using Plotly
810
+ fig = go.Figure()
811
+
812
+ # Add traces for each root's imaginary part
813
+ fig.add_trace(go.Scatter(
814
+ x=z_values,
815
+ y=ims_values1,
816
+ mode='lines',
817
+ name='Im(s₁)',
818
+ line=dict(color='rgb(220, 60, 60)', width=3),
819
+ hovertemplate='z: %{x:.3f}<br>Im(s₁): %{y:.6f}<extra>Root 1</extra>'
820
+ ))
821
+
822
+ fig.add_trace(go.Scatter(
823
+ x=z_values,
824
+ y=ims_values2,
825
+ mode='lines',
826
+ name='Im(s₂)',
827
+ line=dict(color='rgb(60, 60, 220)', width=3),
828
+ hovertemplate='z: %{x:.3f}<br>Im(s₂): %{y:.6f}<extra>Root 2</extra>'
829
+ ))
830
+
831
+ fig.add_trace(go.Scatter(
832
+ x=z_values,
833
+ y=ims_values3,
834
+ mode='lines',
835
+ name='Im(s₃)',
836
+ line=dict(color='rgb(30, 180, 30)', width=3),
837
+ hovertemplate='z: %{x:.3f}<br>Im(s₃): %{y:.6f}<extra>Root 3</extra>'
838
+ ))
839
+
840
+ # Configure layout for better appearance
841
+ fig.update_layout(
842
+ title={
843
+ 'text': f'Im(s) vs z Analysis: a={cubic_a}, y={cubic_y}, β={cubic_beta}',
844
+ 'font': {'size': 24, 'color': '#1E88E5'},
845
+ 'y': 0.95,
846
+ 'x': 0.5,
847
+ 'xanchor': 'center',
848
+ 'yanchor': 'top'
849
+ },
850
+ xaxis={
851
+ 'title': 'z (logarithmic scale)',
852
+ 'titlefont': {'size': 18, 'color': '#424242'},
853
+ 'tickfont': {'size': 14},
854
+ 'gridcolor': 'rgba(220, 220, 220, 0.5)',
855
+ 'showgrid': True,
856
+ 'type': 'log' # Use logarithmic scale for better visualization
857
+ },
858
+ yaxis={
859
+ 'title': 'Im(s)',
860
+ 'titlefont': {'size': 18, 'color': '#424242'},
861
+ 'tickfont': {'size': 14},
862
+ 'gridcolor': 'rgba(220, 220, 220, 0.5)',
863
+ 'showgrid': True
864
+ },
865
+ plot_bgcolor='rgba(240, 240, 240, 0.8)',
866
+ paper_bgcolor='rgba(249, 249, 249, 0.8)',
867
+ hovermode='closest',
868
+ legend={
869
+ 'font': {'size': 14},
 
 
 
 
 
 
 
 
 
 
 
 
870
  'bgcolor': 'rgba(255, 255, 255, 0.9)',
871
+ 'bordercolor': 'rgba(200, 200, 200, 0.5)',
872
+ 'borderwidth': 1
873
+ },
874
+ margin={'l': 60, 'r': 30, 't': 100, 'b': 60},
875
+ height=600,
876
+ annotations=[
877
+ {
878
+ 'text': f"Cubic Equation: {cubic_a}zs³ + [{cubic_a+1}z+{cubic_a}(1-{cubic_y})]s² + [z+{cubic_a+1}-{cubic_y}-{cubic_y*cubic_beta}({cubic_a-1})]s + 1 = 0",
879
+ 'xref': 'paper', 'yref': 'paper',
880
+ 'x': 0.5, 'y': 0.02,
881
+ 'showarrow': False,
882
+ 'font': {'size': 12, 'color': 'black'},
883
+ 'bgcolor': 'rgba(255, 255, 255, 0.9)',
884
+ 'bordercolor': 'rgba(0, 0, 0, 0.5)',
885
+ 'borderwidth': 1,
886
+ 'borderpad': 4,
887
+ 'align': 'center'
888
+ }
889
+ ]
890
+ )
891
+
892
+ # Add custom modebar buttons
893
+ fig.update_layout(
894
+ modebar_add=[
895
+ 'drawline', 'drawopenpath', 'drawclosedpath',
896
+ 'drawcircle', 'drawrect', 'eraseshape'
897
+ ],
898
+ modebar_remove=['lasso2d', 'select2d'],
899
+ dragmode='zoom'
900
+ )
901
+
902
+ # Clear progress container
903
+ progress_container.empty()
904
+
905
+ # Display the interactive plot in Streamlit
906
+ st.plotly_chart(fig, use_container_width=True)
907
+
908
+ # Add explanation text
909
+ st.markdown("""
910
+ ### Explanation of the Analysis
911
+
912
+ This plot shows the imaginary parts of the three roots (s₁, s₂, s₃) of the cubic equation as a function of z.
913
+ The cubic equation being solved is:
914
+
915
+ ```
916
+ zas³ + [z(a+1)+a(1-y)]s² + [z+(a+1)-y-yβ(a-1)]s + 1 = 0
917
+ ```
918
+
919
+ Where a, y, and β are parameters you can adjust in the control panel. The imaginary parts of the roots represent
920
+ oscillatory behavior in the system.
921
+
922
+ - When Im(s) = 0, the root is purely real
923
+ - When Im(s) ≠ 0, the root has an oscillatory component
924
+ """)
925
+
926
+ except json.JSONDecodeError as e:
927
+ st.error(f"Error parsing JSON results: {str(e)}")
928
+ if os.path.exists(data_file):
929
+ with open(data_file, 'r') as f:
930
+ content = f.read()
931
+ st.code(content[:1000] + "..." if len(content) > 1000 else content)
932
 
933
  except Exception as e:
934
  st.error(f"An error occurred: {str(e)}")
 
1028
  # Show placeholder
1029
  st.info("👈 Set parameters and click 'Generate Im(s) vs z Analysis' to create a visualization.")
1030
 
1031
+ st.markdown('</div>', unsafe_allow_html=True)
1032
+
1033
+ # Add footer with instructions
1034
+ st.markdown("""
1035
+ ---
1036
+ ### Instructions for Using the Dashboard
1037
+
1038
+ 1. **Select a tab** at the top to choose between Eigenvalue Analysis and Im(s) vs z Analysis
1039
+ 2. **Adjust parameters** in the left panel to configure your analysis
1040
+ 3. **Click the Generate button** to run the analysis with the selected parameters
1041
+ 4. **Explore the results** in the interactive plot
1042
+ 5. For advanced users, you can enable **Debug Mode** to see detailed output
1043
+
1044
+ If you encounter any issues with compilation, try clicking the "Recompile C++ Code" button in the sidebar.
1045
+ """)