Spaces:
Sleeping
Sleeping
import streamlit as st | |
import subprocess | |
import os | |
import json | |
import numpy as np | |
import matplotlib.pyplot as plt | |
from PIL import Image | |
import time | |
import io | |
# Set page config | |
st.set_page_config( | |
page_title="Eigenvalue Analysis", | |
page_icon="📊", | |
layout="wide" | |
) | |
# Title and description | |
st.title("Eigenvalue Analysis Visualization") | |
st.markdown(""" | |
This application visualizes eigenvalue analysis for matrices with specific properties. | |
Adjust the parameters below to generate a plot showing the relationship between empirical | |
and theoretical eigenvalues. | |
""") | |
# Create output directory in the current working directory | |
current_dir = os.getcwd() | |
output_dir = os.path.join(current_dir, "output") | |
os.makedirs(output_dir, exist_ok=True) | |
# Compile the C++ code at runtime | |
cpp_file = os.path.join(current_dir, "app.cpp") | |
executable = os.path.join(current_dir, "eigen_analysis") | |
# Check if cpp file exists | |
if not os.path.exists(cpp_file): | |
st.error(f"C++ source file not found at: {cpp_file}") | |
st.stop() | |
# Compile the C++ code with the right OpenCV libraries | |
try: | |
st.info("Compiling C++ code...") | |
compile_commands = [ | |
f"g++ -o {executable} {cpp_file} `pkg-config --cflags --libs opencv4` -std=c++11", | |
f"g++ -o {executable} {cpp_file} `pkg-config --cflags --libs opencv` -std=c++11", | |
f"g++ -o {executable} {cpp_file} -I/usr/include/opencv4 -lopencv_core -lopencv_imgproc -std=c++11" | |
] | |
compiled = False | |
for cmd in compile_commands: | |
compile_result = subprocess.run( | |
cmd, | |
shell=True, | |
capture_output=True, | |
text=True | |
) | |
if compile_result.returncode == 0: | |
compiled = True | |
break | |
if not compiled: | |
st.error("All compilation attempts failed. Please check the system requirements.") | |
st.stop() | |
# Make sure the executable is executable | |
os.chmod(executable, 0o755) | |
st.success("C++ code compiled successfully") | |
except Exception as e: | |
st.error(f"Error during compilation: {str(e)}") | |
st.stop() | |
# Input parameters sidebar | |
st.sidebar.header("Parameters") | |
# Parameter inputs with defaults and validation | |
n = st.sidebar.number_input("Sample size (n)", min_value=5, max_value=1000, value=100, step=5, help="Number of samples") | |
p = st.sidebar.number_input("Dimension (p)", min_value=5, max_value=1000, value=50, step=5, help="Dimensionality") | |
a = st.sidebar.number_input("Value for a", min_value=1.1, max_value=10.0, value=2.0, step=0.1, help="Parameter a > 1") | |
# Automatically calculate y = p/n (as requested) | |
y = p/n | |
st.sidebar.text(f"Value for y = p/n: {y:.4f}") | |
# Add fineness control | |
fineness = st.sidebar.slider( | |
"Calculation fineness", | |
min_value=20, | |
max_value=500, | |
value=100, | |
step=10, | |
help="Higher values give smoother curves but take longer to calculate" | |
) | |
# Generate button | |
if st.sidebar.button("Generate Plot", type="primary"): | |
# Show progress | |
progress_bar = st.progress(0) | |
status_text = st.empty() | |
try: | |
# Run the C++ executable with the parameters in JSON output mode | |
data_file = os.path.join(output_dir, "eigenvalue_data.json") | |
# Delete previous output if exists | |
if os.path.exists(data_file): | |
os.remove(data_file) | |
# Execute the C++ program | |
cmd = [executable, str(n), str(p), str(a), str(y), str(fineness), data_file] | |
process = subprocess.Popen( | |
cmd, | |
stdout=subprocess.PIPE, | |
stderr=subprocess.PIPE, | |
text=True | |
) | |
# Show output in a status area | |
status_text.text("Starting calculations...") | |
last_progress = 0 | |
while process.poll() is None: | |
output = process.stdout.readline() | |
if output: | |
if output.startswith("PROGRESS:"): | |
try: | |
# Update progress bar | |
progress_value = float(output.split(":")[1].strip()) | |
progress_bar.progress(progress_value) | |
last_progress = progress_value | |
status_text.text(f"Calculating... {int(progress_value * 100)}% complete") | |
except: | |
pass | |
else: | |
status_text.text(output.strip()) | |
time.sleep(0.1) | |
return_code = process.poll() | |
if return_code != 0: | |
error = process.stderr.read() | |
st.error(f"Error executing the analysis: {error}") | |
else: | |
progress_bar.progress(1.0) | |
status_text.text("Calculations complete! Generating plot...") | |
# Load the results from the JSON file | |
with open(data_file, 'r') as f: | |
data = json.load(f) | |
# Create a better plot with matplotlib | |
beta_values = np.array(data['beta_values']) | |
max_eigenvalues = np.array(data['max_eigenvalues']) | |
min_eigenvalues = np.array(data['min_eigenvalues']) | |
theoretical_max = np.array(data['theoretical_max']) | |
theoretical_min = np.array(data['theoretical_min']) | |
# Create the plot | |
fig, ax = plt.subplots(figsize=(12, 9), dpi=100) | |
# Set the background color | |
fig.patch.set_facecolor('#f5f5f5') | |
ax.set_facecolor('#f0f0f0') | |
# Plot the data | |
ax.plot(beta_values, max_eigenvalues, 'r-', linewidth=2, | |
label='Empirical Max Eigenvalue', marker='o', markevery=len(beta_values)//20) | |
ax.plot(beta_values, min_eigenvalues, 'b-', linewidth=2, | |
label='Empirical Min Eigenvalue', marker='o', markevery=len(beta_values)//20) | |
ax.plot(beta_values, theoretical_max, 'g-', linewidth=2, | |
label='Theoretical Max Function', marker='D', markevery=len(beta_values)//20) | |
ax.plot(beta_values, theoretical_min, 'm-', linewidth=2, | |
label='Theoretical Min Function', marker='D', markevery=len(beta_values)//20) | |
# Add grid | |
ax.grid(True, linestyle='--', alpha=0.7) | |
# Set labels and title | |
ax.set_xlabel('β', fontsize=14) | |
ax.set_ylabel('Eigenvalues', fontsize=14) | |
ax.set_title(f'Eigenvalue Analysis: n={n}, p={p}, a={a}, y={y:.4f}', fontsize=16) | |
# Add legend | |
ax.legend(loc='best', fontsize=12, framealpha=0.9) | |
# Add formulas as text | |
formula_text1 = r"Max Function: $\max_{k \in (0,\infty)} \frac{y\beta(a-1)k + (ak+1)((y-1)k-1)}{(ak+1)(k^2+k)y}$" | |
formula_text2 = r"Min Function: $\min_{t \in (-1/a,0)} \frac{y\beta(a-1)t + (at+1)((y-1)t-1)}{(at+1)(t^2+t)y}$" | |
plt.figtext(0.02, 0.02, formula_text1, fontsize=10, color='green') | |
plt.figtext(0.55, 0.02, formula_text2, fontsize=10, color='purple') | |
# Adjust layout | |
plt.tight_layout(rect=[0, 0.05, 1, 0.95]) | |
# Save the plot to a buffer | |
buf = io.BytesIO() | |
plt.savefig(buf, format='png', dpi=100) | |
buf.seek(0) | |
# Save to file | |
output_file = os.path.join(output_dir, "eigenvalue_analysis.png") | |
plt.savefig(output_file, format='png', dpi=100) | |
plt.close() | |
# Display the image in Streamlit | |
status_text.success("Analysis completed successfully!") | |
st.image(buf, use_column_width=True) | |
# Provide download button | |
with open(output_file, "rb") as file: | |
btn = st.download_button( | |
label="Download Plot", | |
data=file, | |
file_name=f"eigenvalue_analysis_n{n}_p{p}_a{a}_y{y:.4f}.png", | |
mime="image/png" | |
) | |
# Add some statistics | |
st.subheader("Statistical Summary") | |
col1, col2 = st.columns(2) | |
with col1: | |
st.write("### Maximum Eigenvalues") | |
st.write(f"Empirical Max: {max(max_eigenvalues):.6f}") | |
st.write(f"Theoretical Max: {max(theoretical_max):.6f}") | |
st.write(f"Difference: {abs(max(max_eigenvalues) - max(theoretical_max)):.6f}") | |
with col2: | |
st.write("### Minimum Eigenvalues") | |
st.write(f"Empirical Min: {min(min_eigenvalues):.6f}") | |
st.write(f"Theoretical Min: {min(theoretical_min):.6f}") | |
st.write(f"Difference: {abs(min(min_eigenvalues) - min(theoretical_min)):.6f}") | |
except Exception as e: | |
st.error(f"An error occurred: {str(e)}") | |
# Show example plot on startup or previous results | |
example_file = os.path.join(output_dir, "eigenvalue_analysis.png") | |
if os.path.exists(example_file): | |
# Show the most recent plot by default | |
st.subheader("Current Plot") | |
img = Image.open(example_file) | |
st.image(img, use_column_width=True) | |
else: | |
st.info("👈 Set parameters and click 'Generate Plot' to create a visualization.") | |
# Add information about the analysis | |
with st.expander("About Eigenvalue Analysis"): | |
st.markdown(""" | |
## Theory | |
This application visualizes the relationship between empirical and theoretical eigenvalues for matrices with specific properties. | |
The analysis examines: | |
- **Empirical Max/Min Eigenvalues**: The maximum and minimum eigenvalues calculated from the generated matrices | |
- **Theoretical Max/Min Functions**: The theoretical bounds derived from mathematical analysis | |
### Key Parameters | |
- **n**: Sample size | |
- **p**: Dimension | |
- **a**: Value > 1 that affects the distribution of eigenvalues | |
- **y**: Value calculated as p/n that affects scaling | |
- **Fineness**: Controls the number of points calculated along the β range (0 to 1) | |
### Mathematical Formulas | |
Max Function: | |
max{k ∈ (0,∞)} [yβ(a-1)k + (ak+1)((y-1)k-1)]/[(ak+1)(k²+k)y] | |
Min Function: | |
min{t ∈ (-1/a,0)} [yβ(a-1)t + (at+1)((y-1)t-1)]/[(at+1)(t²+t)y] | |
""") |