def steepest_descent(A, b, x_init=None, M=10000, ε=10e-10, check_spd=True): """ finds a solution to the linear system Ax = b via steepest descent inputs: A is an nxn SPD matrix b is an n x 1 vector x0 is the initial estimate vector (nx1) (default is zero vector) M is max number of iterations (default 10000) ε is machine precision (default .0001) if check_spd, the program will fail in the event that the system is not spd note: - uses size of || x_{k+1} - x_k ||_2^2 as stopping condition - please don't break this code with weird stuff (more testing needed) """ if not spd(A): raise Exception(""" A must be positive definite! pass check_spd=False to bypass""") # initialize x_0 as zero vector if one wasn't provided if x_init is None: x = np.zeros_like(b, np.float) else: x = x_init for k in range(M): v = b - A.dot(x) u = A.dot(v) t = v.T.dot(v) / u.T.dot(v) x, x_old = ( x + t*v , x) x_change = norm(x-x_old) if x_change < ε: break #print(locals()) #input('...') else: print('warning: exhausted max iterations (M={})'.format(M)) summary = "terminated in {} iterations (out of M={}) with tolerance ε={}".format(k+1, M, ε) print(summary) return x
def conjugate_gradient(A, b, M=10000, x=None, tol=10e-10, check_spd=True): """ conjugate gradient solution of Ax = b INPUTS A: a nxn array representing a symmetric positive definite matrix b: a nx1 array M: max iterations to run (see below) x: a starting guess (default is zero vector) tol: tolerance (used for stopping condition) check_spd: pre-check that A is in fact symmetric positive definite OUTPUT x: the approximate solution to the system Ax=b NOTES: - M should be superfluous; theoretically this method with terminate successfuly in n == b.size iterations, provided A is s.p.d. No such guarantee is made if A is not s.p.d. - Similarly, a starting guess of x=0 is typically desired, as it minimizes computational error. - If A is not symmetric positive definite and check_spd==True, then a generic Exception will be thrown, terminating execution. """ assert A.shape[1] == b.shape[0], "system doesn't match" if not spd(A): raise Exception(""" A is not positive definite; aborting. pass check_false=False to bypass""") # set an initial guess or check inputted if x is None: x = np.zeros_like(b) # creates an nx1 zero vector else: assert x.shape == b.shape, "system doesn't match" r = b - A.dot(x) c = vdot(r,r) v = r for i in range(M): if np.sqrt(c) < tol: print("tolerance reached!") break u = A.dot(v) alpha = c / (u.T.dot(v)) x = x + alpha*v r = r - alpha*u d = vdot(r,r) if np.sqrt(d) < tol: print("tolerance reached!") break else: v = r + (d/c)*v c = d else: print("max ({}) iterations exhausted".format(i+1)) print("finished in {} iterations".format(i)) return x