File size: 3,835 Bytes
c7544bc
 
 
 
 
 
38fc399
c7544bc
 
509fadc
c7544bc
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
38fc399
c7544bc
 
 
 
 
 
251c397
bfc5dfe
 
 
c7544bc
38fc399
c7544bc
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
38fc399
 
 
 
c7544bc
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
251c397
c7544bc
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
# Import required libraries
import numpy as np
import matplotlib.pyplot as plt
import streamlit as st
import sympy as sp

# Pre-defined functions and their derivatives
def square(x): 
    return x**2
 
def derivative_square(x):
    return 2*x

def cube(x): 
    return x**3

def derivative_cube(x):
    return 3 * x**2

def sin(x):
    return np.sin(x)

def derivative_sin(x):
    return np.cos(x)
    
def inverse(x):
    return 1/x

def derivative_inverse(x):
    return - (1 / x **2)

def poly(x):
    return x + 2 * (x**2) + (0.4) * x**3

def derivative_poly(x):
    return 1 + 4 * x + 1.2 * x**2

# Function to calculate the derivative using SymPy
def calculate_derivative(func_str):
    x = sp.symbols('x')
    try:
        # Parse the function string into a sympy expression
        func = sp.sympify(func_str)
        # Calculate the derivative
        derivative = sp.diff(func, x) 
        func_lambdified = sp.lambdify(x, func, "numpy")
        derivative_lambdified = sp.lambdify(x, derivative, "numpy")
        return func_lambdified, derivative_lambdified
    except sp.SympifyError:
        st.error("Invalid function input. Please enter a valid mathematical expression.")
        return None, None

# Title
st.title('Gradient Descent Visualizer')
st.sidebar.title("It's your turn..")

# User input
function = st.sidebar.selectbox('Pre Defined Functions', ['Square', 'Cube', 'Polynomial', 'sin', '1/x', 'None'])
starting_point = st.sidebar.number_input('Starting Point', value=5, step=1)
learning_rate = st.sidebar.number_input('Learning Rate', value=0.1, step=0.01)

# Define the selected function and its derivative
if function == 'Square':
    func = square
    derivative_func = derivative_square
elif function == 'Cube':
    func = cube
    derivative_func = derivative_cube
elif function == 'Polynomial':
    func = poly
    derivative_func = derivative_poly
elif function == 'sin':
    func = sin
    derivative_func = derivative_sin
elif function == '1/x':
    func = inverse
    derivative_func = derivative_inverse
elif function == 'None':
    user_func = st.sidebar.text_input("Enter a function (in terms of x): ")
    func, derivative_func = calculate_derivative(user_func)
    if func is None:
        st.stop()

# Check if the starting point has changed
if 'last_starting_point' not in st.session_state or st.session_state.last_starting_point != starting_point:
    st.session_state.path = [starting_point]
    st.session_state.iteration = 0  
    st.session_state.last_starting_point = starting_point  

# Perform one iteration of gradient descent
if st.sidebar.button('Next Iteration'):
    current_point = st.session_state.path[-1]
    new_point = current_point - learning_rate * derivative_func(current_point)
    st.session_state.path.append(new_point)
    st.session_state.iteration += 1 

# Create an array of values for plotting
x_values = np.linspace(-10, 10, 500)
y_values = func(x_values)

# Dynamic scaling based on the function's range
y_min, y_max = np.min(y_values), np.max(y_values)
y_padding = (y_max - y_min) * 0.1

# Plot the function and the path of points
plt.figure(figsize=(8, 6))
plt.plot(x_values, y_values, label=function, color='blue')
plt.scatter(st.session_state.path, [func(x) for x in st.session_state.path], color='red', zorder=5)

# Calculate and plot the tangent line
current_point = st.session_state.path[-1]
slope = derivative_func(current_point)
y_tangent = slope * (x_values - current_point) + func(current_point)
plt.plot(x_values, y_tangent, '--', color='red')

# Set plot limits dynamically
plt.xlim([-10, 10])
plt.ylim([y_min - y_padding, y_max + y_padding])

# Display the iteration number
plt.title(f'Iteration: {st.session_state.iteration}')

# Labels and legend
plt.xlabel('x')
plt.ylabel('f(x)')
plt.legend()
plt.grid(True)

# Display the plot
st.pyplot(plt)