add homework11
This commit is contained in:
159
homework11/Homework11_Q5.py
Normal file
159
homework11/Homework11_Q5.py
Normal file
@@ -0,0 +1,159 @@
|
|||||||
|
import numpy as np
|
||||||
|
import matplotlib.pyplot as plt
|
||||||
|
|
||||||
|
# --- 1. Define Function, Gradient, and Hessian ---
|
||||||
|
# Objective function: Rosenbrock function
|
||||||
|
def objective_function(x):
|
||||||
|
x1, x2 = x[0], x[1]
|
||||||
|
return 100 * (x2 - x1**2)**2 + (1 - x1)**2
|
||||||
|
|
||||||
|
# Gradient vector calculation
|
||||||
|
def gradient(x):
|
||||||
|
x1, x2 = x[0], x[1]
|
||||||
|
df_dx1 = -400 * x1 * (x2 - x1**2) - 2 * (1 - x1)
|
||||||
|
df_dx2 = 200 * (x2 - x1**2)
|
||||||
|
return np.array([df_dx1, df_dx2])
|
||||||
|
|
||||||
|
# Hessian matrix calculation
|
||||||
|
def hessian(x):
|
||||||
|
x1, x2 = x[0], x[1]
|
||||||
|
d2f_dx1dx1 = -400 * (x2 - 3 * x1**2) + 2
|
||||||
|
d2f_dx1dx2 = -400 * x1
|
||||||
|
d2f_dx2dx1 = -400 * x1
|
||||||
|
d2f_dx2dx2 = 200
|
||||||
|
return np.array([[d2f_dx1dx1, d2f_dx1dx2], [d2f_dx2dx1, d2f_dx2dx2]])
|
||||||
|
|
||||||
|
# --- 2. Backtracking Line Search ---
|
||||||
|
def backtracking_line_search(x, p, grad, alpha_bar=1.0, rho=0.5, c1=1e-3):
|
||||||
|
"""
|
||||||
|
Finds a step size alpha that satisfies the 1st Wolfe condition (Armijo condition).
|
||||||
|
Condition: f(x + alpha*p) <= f(x) + c1 * alpha * grad^T * p
|
||||||
|
"""
|
||||||
|
alpha = alpha_bar
|
||||||
|
f_val = objective_function(x)
|
||||||
|
grad_dot_p = np.dot(grad, p)
|
||||||
|
|
||||||
|
# Loop until condition is met
|
||||||
|
while objective_function(x + alpha * p) > f_val + c1 * alpha * grad_dot_p:
|
||||||
|
alpha *= rho
|
||||||
|
# Safety break to prevent infinite loops if alpha becomes too small
|
||||||
|
if alpha < 1e-16:
|
||||||
|
break
|
||||||
|
return alpha
|
||||||
|
|
||||||
|
# --- 3. Optimization Algorithms ---
|
||||||
|
def run_optimization(method, x0, tol_ratio=1e-12, max_iter=20000):
|
||||||
|
"""
|
||||||
|
Runs the specified optimization method.
|
||||||
|
Returns: list of alphas used, total iterations
|
||||||
|
"""
|
||||||
|
x = x0.copy()
|
||||||
|
grad_0_norm = np.linalg.norm(gradient(x0))
|
||||||
|
|
||||||
|
alphas = []
|
||||||
|
|
||||||
|
print(f"[{method}] Starting from {x0}...")
|
||||||
|
|
||||||
|
for i in range(max_iter):
|
||||||
|
grad = gradient(x)
|
||||||
|
grad_norm = np.linalg.norm(grad)
|
||||||
|
|
||||||
|
# Convergence Check: ||grad f(xk)|| < 10^-12 * ||grad f(x0)||
|
||||||
|
if grad_norm < tol_ratio * grad_0_norm:
|
||||||
|
print(f" -> Converged at iteration {i}. Final Loss: {objective_function(x):.6e}")
|
||||||
|
return alphas, i
|
||||||
|
|
||||||
|
# Determine Search Direction
|
||||||
|
if method == "Steepest_Descent":
|
||||||
|
direction = -grad
|
||||||
|
elif method == "Newton":
|
||||||
|
hess = hessian(x)
|
||||||
|
try:
|
||||||
|
# Solve H * d = -g for d
|
||||||
|
direction = np.linalg.solve(hess, -grad)
|
||||||
|
except np.linalg.LinAlgError:
|
||||||
|
# Fallback if Hessian is singular
|
||||||
|
direction = -grad
|
||||||
|
|
||||||
|
# Perform Backtracking Line Search
|
||||||
|
alpha = backtracking_line_search(x, direction, grad, alpha_bar=1.0, rho=0.5, c1=1e-3)
|
||||||
|
|
||||||
|
# Update Position
|
||||||
|
x = x + alpha * direction
|
||||||
|
|
||||||
|
alphas.append(alpha)
|
||||||
|
|
||||||
|
print(f" -> Did not converge within {max_iter} iterations.")
|
||||||
|
print(f" -> Final Gradient Norm: {grad_norm:.6e}")
|
||||||
|
return alphas, max_iter
|
||||||
|
|
||||||
|
# --- 4. Main Execution and Plotting ---
|
||||||
|
|
||||||
|
# Configuration
|
||||||
|
initial_points = [np.array([1.2, 1.2]), np.array([-1.2, 1.0])]
|
||||||
|
methods = ["Steepest_Descent", "Newton"]
|
||||||
|
|
||||||
|
# Dictionary to hold simulation results
|
||||||
|
results = {}
|
||||||
|
|
||||||
|
# Run simulations
|
||||||
|
for x0 in initial_points:
|
||||||
|
for method in methods:
|
||||||
|
# Construct a unique key for storage
|
||||||
|
key = f"{method}_x0_{x0}"
|
||||||
|
alphas, num_iters = run_optimization(method, x0)
|
||||||
|
results[key] = {'alphas': alphas, 'iters': num_iters, 'x0': x0}
|
||||||
|
|
||||||
|
# Plot configuration
|
||||||
|
fig, axes = plt.subplots(2, 2, figsize=(14, 10))
|
||||||
|
plt.subplots_adjust(hspace=0.4, wspace=0.3)
|
||||||
|
|
||||||
|
# Mapping results to subplots
|
||||||
|
plot_mapping = {
|
||||||
|
("Steepest_Descent", str(initial_points[0])): (0, 0),
|
||||||
|
("Newton", str(initial_points[0])): (0, 1),
|
||||||
|
("Steepest_Descent", str(initial_points[1])): (1, 0),
|
||||||
|
("Newton", str(initial_points[1])): (1, 1),
|
||||||
|
}
|
||||||
|
|
||||||
|
for key, data in results.items():
|
||||||
|
method_name = key.split("_x0_")[0]
|
||||||
|
x0_str = str(data['x0'])
|
||||||
|
|
||||||
|
ax_idx = plot_mapping[(method_name, x0_str)]
|
||||||
|
ax = axes[ax_idx]
|
||||||
|
|
||||||
|
y_data = data['alphas']
|
||||||
|
x_data = range(len(y_data))
|
||||||
|
|
||||||
|
# --- PLOTTING LOGIC MODIFICATION ---
|
||||||
|
# For Steepest Descent, show only first {limit} steps
|
||||||
|
if method_name == "Steepest_Descent":
|
||||||
|
limit = 30
|
||||||
|
if len(y_data) > limit:
|
||||||
|
y_data = y_data[:limit]
|
||||||
|
x_data = range(limit)
|
||||||
|
title_suffix = f" (First {limit} Steps Shown)"
|
||||||
|
else:
|
||||||
|
title_suffix = ""
|
||||||
|
else:
|
||||||
|
title_suffix = ""
|
||||||
|
|
||||||
|
ax.plot(x_data, y_data, marker='o', linestyle='-', markersize=4, linewidth=1.5)
|
||||||
|
|
||||||
|
# Titles and Labels
|
||||||
|
ax.set_title(f"{method_name}\nStart: {data['x0']}\nTotal Iters: {data['iters']}{title_suffix}")
|
||||||
|
ax.set_xlabel("Iteration")
|
||||||
|
ax.set_ylabel("Step Size (Alpha)")
|
||||||
|
ax.grid(True, which='both', linestyle='--', alpha=0.7)
|
||||||
|
|
||||||
|
# Add annotation for total iterations
|
||||||
|
ax.text(0.95, 0.95, f"Total Iters: {data['iters']}",
|
||||||
|
transform=ax.transAxes,
|
||||||
|
verticalalignment='top', horizontalalignment='right',
|
||||||
|
bbox=dict(boxstyle='round', facecolor='white', alpha=0.8))
|
||||||
|
|
||||||
|
# Save and Show
|
||||||
|
#plt.suptitle("Step Size vs Iteration (Rosenbrock Function)", fontsize=16)
|
||||||
|
plt.savefig("optimization_results.png")
|
||||||
|
#plt.show()
|
||||||
Reference in New Issue
Block a user