import streamlit as st import numpy as np import pandas as pd import base64 import plotly.graph_objects as go st.set_page_config(layout="wide") # Function parser to evaluate the mathematical function def parse_function(func_str, x): try: return eval(func_str) except Exception as e: st.error(f"Error evaluating function: {e}") return np.zeros_like(x) # Compute the gradient (derivative) at a point using numerical differentiation def compute_gradient(func_str, x): delta = 1e-8 grad = (parse_function(func_str, x + delta) - parse_function(func_str, x)) / delta return grad # Streamlit App def encode_image(image_path): with open(image_path, "rb") as image_file: return base64.b64encode(image_file.read()).decode() def add_bg_from_local(image_file): encoded_string = encode_image(image_file) st.markdown( f""" """, unsafe_allow_html=True ) add_bg_from_local("Icon/rm183-kul-21.jpg") st.markdown( """ """, unsafe_allow_html=True ) st.markdown(""" """, unsafe_allow_html=True) file_ = open("Icon/wave-chart-ezgif.com-gif-maker.gif", "rb").read() base64_gif = base64.b64encode(file_).decode("utf-8") st.markdown( f"""

Interactive Gradient Descent Visualizer Icon

""", unsafe_allow_html=True ) st.markdown("""

Explore how gradient descent works visually and interactively. Adjust parameters and watch as the algorithm converges towards the minimum of a function.

""", unsafe_allow_html=True) st.sidebar.header("Input Parameters") # Dropdown menu function_options = ["x**2", "x**3", "np.sin(x)", "1/x", "Custom Polynomial"] selected_function = st.sidebar.selectbox("Choose a function:", function_options) if selected_function == "Custom Polynomial": func_str = st.sidebar.text_input("Enter custom polynomial in terms of x:", value="x**2 - 4*x + 4") else: func_str = st.sidebar.text_input(f"Modify the selected function ({selected_function}):", value=selected_function) # Initialize session state variables if not already initialized if "x_vals" not in st.session_state: st.session_state.x_vals = [] if "y_vals" not in st.session_state: st.session_state.y_vals = [] if "current_step" not in st.session_state: st.session_state.current_step = 0 # Input for initial x point and learning rate initial_x = st.sidebar.number_input("Initial Point (x):", value=0.00) learning_rate = st.sidebar.number_input("Learning Rate:", value=0.1, step=0.01, format="%.2f") # Update session state with initial values if st.session_state.current_step == 0: st.session_state.x_vals = [initial_x] st.session_state.y_vals = [parse_function(func_str, initial_x)] col1, col2 = st.sidebar.columns(2) if col1.button("Reset Graph"): st.session_state.x_vals = [initial_x] st.session_state.y_vals = [parse_function(func_str, initial_x)] st.session_state.current_step = 0 if col2.button("Next Iteration"): current_x = st.session_state.x_vals[-1] grad = compute_gradient(func_str, current_x) next_x = current_x - learning_rate * grad st.session_state.x_vals.append(next_x) st.session_state.y_vals.append(parse_function(func_str, next_x)) st.session_state.current_step += 1 x_vals = np.linspace(-20, 30, 1000) y_vals = parse_function(func_str, x_vals) fig = go.Figure() # Add the function curve to the plot fig.add_trace(go.Scatter(x=x_vals, y=y_vals, mode='lines', name='Function Curve', line=dict(color='teal'))) # Add the gradient descent steps (if any) if st.session_state.current_step > 0: fig.add_trace(go.Scatter( x=st.session_state.x_vals, y=st.session_state.y_vals, mode='markers+lines', name='Gradient Descent Steps', marker=dict(color='red', size=10), line=dict(dash='dash', width=1.5) )) # Function to draw the tangent line at the current point def draw_tangent(fig, func_str, x_point): y_point = parse_function(func_str, x_point) grad = compute_gradient(func_str, x_point) tangent_x = np.linspace(-20, 30, 1000) tangent_y = grad * (tangent_x - x_point) + y_point fig.add_trace(go.Scatter( x=tangent_x, y=tangent_y, mode='lines', name=f'Tangent at x={x_point:.2f}', line=dict(dash='dot', color='green', width=2) )) fig.add_trace(go.Scatter( x=[x_point], y=[y_point], mode='markers', name='Tangent Point', marker=dict(color='blue', size=12, symbol='circle') )) # Draw tangent at the last gradient descent point if len(st.session_state.x_vals) > 0: draw_tangent(fig, func_str, st.session_state.x_vals[-1]) fig.update_layout( shapes=[ dict(type="line", x0=-20, y0=0, x1=30, y1=0, line=dict(color="black", width=2)), dict(type="line", x0=0, y0=-110, x1=0, y1=120, line=dict(color="black", width=2)) ], xaxis=dict( title='x', range=[-20, 30], showline=True, linecolor='black', linewidth=2, mirror=True, ticks='inside', tickfont=dict(color='black'), titlefont=dict(color='black'), ), yaxis=dict( title='y', range=[-110, 120], showline=True, linecolor='Black', linewidth=2, mirror=True, ticks='inside', tickfont=dict(color='black'), titlefont=dict(color='black'), ), plot_bgcolor= 'rgba(0, 0, 0, 0)', paper_bgcolor= 'rgba(0, 0, 0, 0)', font=dict(color='black'), legend=dict( font=dict(color='black'), x=1.05, xanchor='left', y=1, yanchor='top' ), width=800, height=500, template="plotly_white", title="Gradient Descent on the Selected Function", titlefont=dict(color='black'), margin=dict(l=50, r=50, t=50, b=50), ) st.plotly_chart(fig, use_container_width=True) if st.session_state.current_step > 0: iteration_data = { "Iteration": list(range(st.session_state.current_step + 1)), "x Value": [f"{x_val:.5f}" for x_val in st.session_state.x_vals], "y Value": [f"{y_val:.5f}" for y_val in st.session_state.y_vals] } iteration_df = pd.DataFrame(iteration_data) st.markdown("

Iteration Details

", unsafe_allow_html=True) st.markdown( iteration_df.to_html(index=False, escape=False), unsafe_allow_html=True ) st.markdown(""" """, unsafe_allow_html=True) st.sidebar.subheader("Current Status") st.sidebar.write(f"Iteration: {st.session_state.current_step}") st.sidebar.write(f"Current x: {st.session_state.x_vals[-1]:.5f}") st.sidebar.write(f"Current y: {st.session_state.y_vals[-1]:.5f}")