Skip to content
New Workbook
Sign up
Optimization in Python
import numpy as np
import matplotlib.pyplot as plt
from scipy.optimize import minimize

Gradient descent

# Function to minimize: f(x) = (x - 3)^2
def function(x):
    return (x - 3) ** 2

# Derivative of the function: f'(x) = 2 * (x - 3)
def derivative(x):
    return 2 * (x - 3)

# Gradient Descent function
def gradient_descent(starting_point, learning_rate, n_iterations):
    x = starting_point
    points = []  # To store points at each iteration

    for _ in range(n_iterations):
        points.append(x)
        gradient = derivative(x)
        x -= learning_rate * gradient  # Update x using gradient descent

    return points

# Parameters
starting_point = -7  # Starting point of the algorithm
learning_rate = 0.1  # Learning rate
n_iterations = 25  # Number of iterations

# Get the points from gradient descent
points = gradient_descent(starting_point, learning_rate, n_iterations)

# Create an array of x values for plotting the function
x_values = np.linspace(-8, 8, 400)
y_values = function(x_values)

# Plot the function and gradient descent steps
plt.figure(figsize=(10, 6))
plt.plot(x_values, y_values, label='f(x) = (x - 3)^2', color='blue')

# Plot gradient descent points
gd_x = np.array(points)
gd_y = function(gd_x)
plt.scatter(gd_x, gd_y, color='red', zorder=5)
plt.plot(gd_x, gd_y, color='red', linestyle='--', marker='o', zorder=4, label='Gradient Descent Steps')

# Highlight the minimum
plt.scatter([3], [0], color='green', zorder=6, marker='x', s=100, label='Minimum')

# Labels and title
plt.title('Gradient Descent on f(x) = (x - 3)^2')
plt.xlabel('x')
plt.ylabel('f(x)')
plt.legend()

# Show the plot
plt.show()

Newton's method

# Function to minimize: f(x) = (x - 3)^2
def function(x):
    return (x - 3) ** 2

# First derivative of the function: f'(x) = 2 * (x - 3)
def first_derivative(x):
    return 2 * (x - 3)

# Second derivative of the function: f''(x) = 2
def second_derivative(x):
    return 2

# Newton's Method function
def newtons_method(starting_point, tolerance=1e-6, max_iterations=25):
    x = starting_point
    points = []  # To store points at each iteration

    for _ in range(max_iterations):
        points.append(x)
        gradient = first_derivative(x)
        hessian = second_derivative(x)
        if hessian == 0:
            break  # Avoid division by zero
        x -= gradient / hessian  # Update x using Newton's Method

        # Check for convergence
        if abs(gradient) < tolerance:
            break

    return points

# Parameters
starting_point = -7  # Starting point of the algorithm

# Get the points from Newton's method
points = newtons_method(starting_point)

# Create an array of x values for plotting the function
x_values = np.linspace(-8, 8, 400)
y_values = function(x_values)

# Plot the function and Newton's method steps
plt.figure(figsize=(10, 6))
plt.plot(x_values, y_values, label='f(x) = (x - 3)^2', color='blue')

# Plot Newton's method points
nm_x = np.array(points)
nm_y = function(nm_x)
plt.scatter(nm_x, nm_y, color='red', zorder=5)
plt.plot(nm_x, nm_y, color='red', linestyle='--', marker='o', zorder=4, label='Newton\'s Method Steps')

# Highlight the minimum
plt.scatter([3], [0], color='green', zorder=6, marker='x', s=100, label='Minimum')

# Labels and title
plt.title('Newton\'s Method on f(x) = (x - 3)^2')
plt.xlabel('x')
plt.ylabel('f(x)')
plt.legend()

# Show the plot
plt.show()

Conjugate gradient method

# Function to minimize: f(x) = x^2 + 2x + 2
def function(x):
    return x**2 + 2*x + 2

# Gradient of the function: f'(x) = 2*x + 2
def gradient(x):
    return 2*x + 2

# Conjugate Gradient Method using Scipy
def conjugate_gradient_method(starting_point):
    # Optimization result
    result = minimize(
        fun=function,             # Objective function
        x0=np.array([starting_point]),  # Initial guess
        jac=gradient,             # Gradient function
        method='CG',              # Optimization method (Conjugate Gradient)
        options={'disp': True, 'return_all': True}  # Display and return all points
    )
    return result

# Parameters
starting_point = -4  # Starting point of the algorithm

# Perform Conjugate Gradient optimization
result = conjugate_gradient_method(starting_point)

# Extract optimization path
points = result.allvecs  # All points visited by CG
points = np.array(points).flatten()  # Flatten to 1D array for plotting

# Create an array of x values for plotting the function
x_values = np.linspace(-6, 2, 400)
y_values = function(x_values)

# Plot the function and Conjugate Gradient method steps
plt.figure(figsize=(10, 6))

# Plot function curve
plt.plot(x_values, y_values, label='f(x) = x^2 + 2x + 2', color='blue', linewidth=2)

# Plot Conjugate Gradient method points
plt.scatter(points, function(points), color='red', zorder=5)
plt.plot(points, function(points), color='red', linestyle='--', marker='o', zorder=4, label='CG Steps')

# Highlight the minimum
plt.scatter([-1], [function(-1)], color='green', zorder=6, marker='x', s=100, label='Minimum')

# Labels and title
plt.title('Conjugate Gradient Method on f(x) = x^2 + 2x + 2')
plt.xlabel('x')
plt.ylabel('f(x)')
plt.legend()

# Ensure grid and plot show
plt.ylim(bottom=min(y_values) - 1, top=max(y_values) + 1)  # Set y-axis limits for better visibility
plt.show()

Quasi-newton methods (BFGS)

# Function to minimize: f(x) = x^2 + 2x + 2
def function(x):
    return x**2 + 2*x + 2

# Gradient of the function: f'(x) = 2*x + 2
def gradient(x):
    return 2*x + 2

# BFGS Method using Scipy
def bfgs_method(starting_point):
    # Optimization result
    result = minimize(
        fun=function,             # Objective function
        x0=np.array([starting_point]),  # Initial guess
        jac=gradient,             # Gradient function
        method='BFGS',            # Optimization method
        options={'disp': True, 'return_all': True}  # Display and return all points
    )
    return result

# Parameters
starting_point = -4  # Starting point of the algorithm

# Perform BFGS optimization
result = bfgs_method(starting_point)

# Extract optimization path
points = result.allvecs  # All points visited by BFGS
points = np.array(points).flatten()  # Flatten to 1D array for plotting

# Create an array of x values for plotting the function
x_values = np.linspace(-6, 2, 400)
y_values = function(x_values)

# Plot the function and BFGS method steps
plt.figure(figsize=(10, 6))

# Plot function curve
plt.plot(x_values, y_values, label='f(x) = x^2 + 2x + 2', color='blue', linewidth=2)

# Plot BFGS method points
plt.scatter(points, function(points), color='red', zorder=5)
plt.plot(points, function(points), color='red', linestyle='--', marker='o', zorder=4, label='BFGS Steps')

# Highlight the minimum
plt.scatter([-1], [function(-1)], color='green', zorder=6, marker='x', s=100, label='Minimum')

# Labels and title
plt.title('BFGS Method on f(x) = x^2 + 2x + 2')
plt.xlabel('x')
plt.ylabel('f(x)')
plt.legend()

# Ensure grid and plot show
plt.ylim(bottom=min(y_values) - 1, top=max(y_values) + 1)  # Set y-axis limits for better visibility
plt.show()

The simplex method

# Linear function to minimize: f(x) = x
def objective_function(x):
    return x

# Constraints: x >= 0
def constraint(x):
    return x >= 0

# Simplex Method for Linear Programming (Manual Implementation)
def simplex_method():
    # Define the initial feasible solution
    x_values = np.linspace(0, 2, 100)  # Range for x
    y_values = objective_function(x_values)  # Compute objective function values

    # Initial solution
    x_start = 0
    optimal_x = x_start
    optimal_value = objective_function(optimal_x)

    # Optimization loop (simple manual iteration for demonstration)
    for x in x_values:
        if constraint(x):
            value = objective_function(x)
            if value < optimal_value:
                optimal_value = value
                optimal_x = x

    return optimal_x, optimal_value, x_values, y_values

# Perform Simplex optimization
optimal_x, optimal_value, x_values, y_values = simplex_method()

# Plotting
plt.figure(figsize=(10, 6))

# Plot the linear function
plt.plot(x_values, y_values, label='f(x) = x', color='blue', linewidth=2)

# Plot Simplex method result
plt.scatter(optimal_x, optimal_value, color='red', zorder=5, label='Optimal Solution')
plt.plot([optimal_x], [optimal_value], 'ro', linestyle='--', zorder=4)  # Mark the optimal point

# Labels and title
plt.title('Simplex Method on Linear Function f(x) = x')
plt.xlabel('x')
plt.ylabel('f(x)')
plt.legend()

# Plot show
plt.show()

Common Python packages

Scipy

# Example of the minimize function 
from scipy.optimize import minimize
def objective_function(x):
    return x[0]**2 + x[1]**2

result = minimize(objective_function, [1, 1], method='BFGS')
print(result.x)  

# Example of the root function 
from scipy.optimize import root

def equations(vars):
    x, y = vars
    return [x + 2*y - 3, x - y - 1]

result = root(equations, [0, 0])
print(result.x)

# Example of the curve_fit
from scipy.optimize import curve_fit
import numpy as np

def model(x, a, b):
    return a * np.exp(b * x)

x_data = np.array([1, 2, 3])
y_data = np.array([2.7, 7.4, 20.1])
params, covariance = curve_fit(model, x_data, y_data)
print(params)

CVXPY