diff --git a/README.md b/README.md index d0cf3024..b4d7adb0 100644 --- a/README.md +++ b/README.md @@ -1,31 +1,33 @@ # SP4E Homeworks Students: * Lars B. * Bertil T. In this repository, we will keep all homeworks for SP4E ## Homework 1 -See folder named *hw1-conjugate-gradient* +See folder named *hw1-conjugate-gradient*. #### Requirements * Numpy * Scipy * Matplotlib * Argparse The code as been tested with Python 3. #### Usage Run the *main_minimize.py* with the following arguments: * -A < matrix elements in row major order > * -b < vector elements > * -x0 < initial guess elements > * -method < CG-scipy or CG-ours > * -plot < True or False > #### Example -The following command will run the program with the example values given in Exercise 1: +The following command will run the program with the coefficients given in Exercise 1: -python main_minimize.py -A 4 0 1 3 -b 0 1 -method CG-scipy -plot True -x0 4 4 +python main_minimize.py -A 8 0 2 6 -b 0 1 -x0 4 4 -method CG-scipy -plot True + +NB: Note the scaling of S(x) with 1/2 between Ex 1 and 2. diff --git a/hw1-conjugate-gradient/plotting.py b/hw1-conjugate-gradient/plotting.py index 48507426..7f9d6f6a 100644 --- a/hw1-conjugate-gradient/plotting.py +++ b/hw1-conjugate-gradient/plotting.py @@ -1,102 +1,102 @@ import numpy as np import sys import matplotlib.pyplot as plt from matplotlib import cm from mpl_toolkits.mplot3d import Axes3D from quadratic_function import quadratic_function # This function plots the S(x) surface and includes the path taken by the minimizer def plotting(dim, steps, x0, *args): # If we are just dealing with scalars if dim == 1: # Create figure fig = plt.figure(figsize=(14,8)) axe = fig.add_subplot(111) # Discretization of plot num_of_points = 100 # Upper and lower bound of plot xmin = min(x0[0], -5) xmax = max(x0[0], +5) # Discretized x X = np.linspace(xmin,xmax,num_of_points) # Initialize S(x) Z = np.zeros_like(X) # Fill S(x) for i in range(0,num_of_points): Z[i] = quadratic_function( np.array([ X[i] ]), *args ) # Make the plot of S(x) sp = axe.plot(X, Z, 'b-') # Initialize step values step_value = np.zeros(steps.shape[0]) # Fill step values for i in range(0, steps.shape[0]): step_value[i] = quadratic_function( np.array([ steps[i, 0] ]), *args ) # Plot the steps taken in the same plot axe.plot(steps[:,0], step_value, 'r*--') # Set label and save plot axe.set_xlabel('x', fontsize=15) axe.set_ylabel('S(x)', fontsize=15) plt.savefig("plot_1d.png") # If \bf{x} = (x, y) elif dim == 2: # Create figure fig = plt.figure(figsize=(14,8)) axe = fig.add_subplot(111, projection="3d") # Discretization of plot num_of_points = 100 # Upper and lower bound of plot xmin = min(x0[0], -5) xmax = max(x0[0], +5) ymin = min(x0[1], -5) ymax = max(x0[1], +5) # Discretized x on a mesh X, Y = np.meshgrid(np.linspace(xmin,xmax,num_of_points), np.linspace(ymin,ymax,num_of_points)) # Initialize S(x,y) Z = np.zeros_like(X) # Fill S(x, y) for i in range(0,num_of_points): for j in range(0, num_of_points): Z[i,j] = quadratic_function( np.array([X[i,j], Y[i,j]]), *args ) # Make the plot of S(x) sp = axe.plot_surface(X, Y, Z, cmap=cm.coolwarm) axe.view_init(60, 100) fig.colorbar(sp) # Initialize step values step_value = np.zeros(steps.shape[0]) # Fill step values for i in range(0, steps.shape[0]): step_value[i] = quadratic_function( np.array([steps[i, 0], steps[i, 1]]), *args ) # Plot the steps taken in the same plot axe.plot(steps[:,0], steps[:,1], step_value, 'r*--') # Set label and save plot axe.set_xlabel('x', fontsize=15) axe.set_ylabel('y', fontsize=15) axe.set_zlabel(' S(x,y)', fontsize=15) axe.zaxis.set_rotate_label(False) plt.savefig("plot_2d.png") - # If higher dimensions + # If higher dimensions else: print("Cannot make a high dimensional plot") diff --git a/hw1-conjugate-gradient/quadratic_function.py b/hw1-conjugate-gradient/quadratic_function.py index e3b5b4d8..fba92c05 100644 --- a/hw1-conjugate-gradient/quadratic_function.py +++ b/hw1-conjugate-gradient/quadratic_function.py @@ -1,26 +1,31 @@ import numpy as np # This function implements S(x) as given in the exercise sheet + # If matrix A or vector b are not specified through "args", the function assumes # that A and b are those given in Exercise 1 -# Not that you CANNOT only specify A or b, both must be specified such that + +# Note that you CANNOT only specify A or b, both must be specified such that # args[0] = A and args[1] = b + +# Note also that the function is implemented with the factor 1/2 as in Exercise 2 +# Hence the scaling of matrix A with 2 in order to reproduce the case in Exercise 1 def quadratic_function(x, *args): if len(args) == 0: - A = np.array([[4, 0], [1, 3]]) + A = np.array([[4.0, 0], [1, 3]]) * 2.0 b = np.array([0, 1]) else: A = args[0] b = args[1] # reshape into column vectors x.reshape(-1, 1) b.reshape(-1, 1) # return S(x) - return ((x.transpose() @ A) @ x) - (x.transpose() @ b) + return 0.5*((x.transpose() @ A) @ x) - (x.transpose() @ b) # TESTING AND VALIDATING FUNCTION #print(quadratic_function(np.array([1,2]) )) #print(quadratic_function(np.array([1,2]), np.array([[4, 0], [1, 3]]), np.array([0, 1]) ))