u = [] q = [] p = [] v = [] w = [] k = [] for i in range(30): (A, b, c) = input_data(i) x.append(A.shape[0]) y.append(A.shape[1]) (A, c) = stdForm(A, c) (x1, y1, s1) = sp(A, c, b) (x2, y2, s2) = sp2(A, c, b) r1 = np.concatenate((np.dot(A, x1) - b, c - s1 - np.dot(A.T, y1))) r2 = np.concatenate((np.dot(A, x2) - b, c - s2 - np.dot(A.T, y2))) w1 = np.divide((np.dot(b, y1) - np.dot(c, x1)), A.shape[1]) w2 = np.divide((np.dot(b, y2) - np.dot(c, x2)), A.shape[1]) # Mehrotra's method u.append("%5.2e" % np.linalg.norm(r1)) q.append("%5.2e" % w1) t = np.divide(np.linalg.norm(r1), w1) p.append(t) # STP1 method v.append("%5.2e" % np.linalg.norm(r2)) w.append("%5.2e" % w2)
def longpath2(A, b, c, gamma=0.001, c_form=0, w=10**(-8), max_it=500, info=0, ip=1): print('\n\tCOMPUTATION OF LPF ALGORITHM 2') # Algorithm in 4 steps: # 0..Input error checking # 1..Find the initial point with Mehrotra's method # 2..obtain the search direction # 3..find the largest step """ Input error checking & construction in a standard form """ if not (isinstance(A, np.ndarray) or isinstance(b, np.ndarray) or isinstance(c, np.ndarray)): raise Exception('Inputs must be a numpy arrays') if c_form == 0: A, c = stdForm(A, c) r_A, c_A = A.shape if not np.linalg.matrix_rank( A) == r_A: # Check full rank matrix:Remove ld rows: A = A[[ i for i in range(r_A) if not np.array_equal(np.linalg.qr(A)[1][i, :], np.zeros(c_A)) ], :] r_A = A.shape[0] # Update no. of rows """ Initial points: Initial infeasible positive (x,y,s) and initial gap g """ if ip == 0: (x, y, s) = sp(A, c, b) else: (x, y, s) = sp2(A, c, b) (x, y, s) = sp(A, c, b) g = np.dot(c, x) - np.dot(y, b) if info == 0: print('\nInitial primal-dual point:\nx = {} \nlambda = {} \ns = {}'. format(x, y, s)) print('Dual initial g: {}.\n'.format("%10.3f" % g)) # Check if (x, y, s) in neighborhood N_inf: mu = np.dot(x, s) / c_A if not (x * s > gamma * mu).all(): print("Initial point is not in N") E = lambda a: (s + a * s1) * (x + a * x1) - (gamma * np.dot( (s + a * s1), (x + a * x1))) / c_A # Function E: set of values in N_(gamma) #%% """ Search vector direction """ '''Modified Newton's method with with normal equations: find the direction vector (y1, s1, x1)''' it = 0 # Num of iterations tm = term(it) # Define tollerance tm = inf u = [] # Construct list of info elements u.append([it, g, x, s, b - np.dot(A, x), c - np.dot(A.T, y) - s]) sig = [] while tm > w: cp = min(0.1, 100 * np.dot(x, s) / c_A) # sigma2 if info == 0: print("\tIteration: {}\n".format(it), end='') print("Centering parameter sigma:{}.\n".format("%10.3f" % cp)) X_inv = np.linalg.inv(np.diag(x)) W1 = X_inv * np.diag(s) # W1 = X^(-1)*S T = np.concatenate((np.zeros((r_A, r_A)), A), axis=1) U = np.concatenate((A.T, -W1), axis=1) V = np.concatenate((T, U), axis=0) rb = b - np.dot(A, x) rc = c - np.dot(A.T, y) - s rxs = -x * s + cp * (sum(x * s) / c_A) * np.ones( c_A) # Newton step toward x*s = sigma*mi r = np.hstack((rb, rc - np.dot(X_inv, rxs))) o = np.linalg.solve(V, r) y1 = o[:r_A] x1 = o[r_A:c_A + r_A] s1 = np.dot(X_inv, rxs) - np.dot(W1, x1) if info == 0: print( 'Search direction vectors: \n delta_x = {} \n delta_lambda = {} \n delta_s = {}.\n' .format(x1.round(decimals=3), y1.round(decimals=3), s1.round(decimals=3))) """ Compute the largest step length & increment of the points and the iteration""" # We find the maximum alpha s. t the next iteration is in N_gamma v = np.arange(0, 1.000, 0.0001) i = len(v) - 1 while i >= 0: if (E(v[i]) > 0).all(): t = v[i] # print('Largest step length:{}'.format("%10.3f"%t)) break else: i -= 1 # Update step x += t * x1 # Current x y += t * y1 # Current y s += t * s1 # Current s rb = b - np.dot(A, x) rc = c - np.dot(A.T, y) - s z = np.dot(c, x) # Current opt. solution g = z - np.dot(y, b) # Current gap it += 1 u.append([it, g, x.copy(), s.copy(), rb.copy(), rc.copy()]) sig.append([cp]) # Termination elements m, n, q = term(it, b, c, rb, rc, z, g) tm = max(m, n, q) if it == max_it: raise TimeoutError("Iterations maxed out") if info == 0: print( '\nCurrent point:\n x = {} \n lambda = {} \n s = {}.\n'.format( x.round(decimals=3), y.round(decimals=3), s.round(decimals=3))) print('Dual next gap: {}.\n'.format("%10.3f" % g)) #%% print_boxed("Found optimal solution of the problem at\n x* = {}.\n\n". format(x.round(decimals=3)) + "Dual gap: {}\n".format("%2.2e" % g) + "Optimal cost: {}\n".format("%10.8E" % z) + "Number of iteration: {}".format(it)) return x, s, u, sig
def aff_an(A, b, c, c_form=0, w=10**(-8), max_iter=500): print('\n\tCOMPUTATION OF PRIMAL-DUAL AFFINE SCALING ALGORITHM') # Algorithm in 4 steps: # 0..Input error checking # 1..Find the initial point with Mehrotra's method # 2..obtain the search direction # 3..find the largest step """ Input error checking """ if not (isinstance(A, np.ndarray) or isinstance(b, np.ndarray) or isinstance(c, np.ndarray)): raise Exception('Inputs must be a numpy arrays') # Construction in a standard form [A | I] if c_form == 0: A, c = stdForm(A, c) r_A, c_A = A.shape """ Check full rank matrix """ if not np.linalg.matrix_rank(A) == r_A: # Remove ld rows: A = A[[ i for i in range(r_A) if not np.array_equal(np.linalg.qr(A)[1][i, :], np.zeros(c_A)) ], :] r_A = A.shape[0] # Update no. of rows """ Initial points """ # Initial infeasible positive (x,y,s) and initial gap g (x, y, s) = sp(A, c, b) g = np.dot(c, x) - np.dot(y, b) print('\nInitial primal-dual point:\n x = {} \n lambda = {} \n s = {}.\n'. format(x, y, s)) print('Dual initial gap: {}.\n'.format("%10.3f" % g)) #%% """ Search vector direction """ it = 0 tm = term(it) u = [] v = [] while tm > w: u.append(sum(x.copy() * s.copy()) / c_A) print("\tIteration: {}\n".format(it)) S_inv = np.linalg.inv(np.diag(s)) W1 = S_inv * np.diag(x) # W1 = D = S^(-1)*X W2 = np.dot(A, W1) # W A*S^(-1)*X W = np.dot(W2, A.T) L = np.linalg.cholesky(W) # CHOLESKY for A* D^2 *A^T L_inv = np.linalg.inv(L) # RHS of the system rb = b - np.dot(A, x) rc = c - np.dot(A.T, y) - s rxs = -x * s # Newton step toward x*s = 0 B = rb + np.dot(W2, rc) - np.dot(np.dot(A, S_inv), rxs) #RHS of normal equation form z = np.dot(L_inv, B) # SEARCH DIRECTION: y1 = np.dot(L_inv.T, z) s1 = rc - np.dot(A.T, y1) x1 = np.dot(S_inv, rxs) - np.dot(W1, s1) q1 = np.concatenate((x1, s1)) v.append(np.linalg.norm(q1)) print( 'Search direction vectors: \n delta_x = {} \n delta_lambda = {} \n delta_s = {}.\n' .format(x1.round(decimals=3), y1.round(decimals=3), s1.round(decimals=3))) #%% """ largest step length """ # Largest step length T such that (x, s) + T (x1, s1) is positive m = min([(-x[i] / x1[i], i) for i in range(c_A) if x1[i] < 0], default=[1])[0] n = min([(-s[i] / s1[i], i) for i in range(c_A) if s1[i] < 0], default=[1])[0] T = (0.9) * min(m, n) # INCREMENT of the vectors and iterations x += min(T, 1) * x1 y += min(T, 1) * y1 s += min(T, 1) * s1 z = np.dot(c, x) # Current optimal solution g = z - np.dot(y, b) it += 1 # Termination elements tm = term(it, b, c, rb, rc, z, g) if it == max_iter: raise TimeoutError("Iterations maxed out") print('Current point:\n x = {} \n lambda = {} \n s = {}.\n'.format( x, y, s)) print('Dual next gap: {}.\n'.format("%10.3f" % g)) print_boxed( "Found optimal solution of the problem at\n x* = {}.\n".format(x) + "Dual gap: {}\n".format("%10.6f" % g) + "Optimal cost: {}\n".format("%10.3f" % z) + "Number of iterations: {}".format(it)) return x, s, u, v
def longpathPC(A, b, c, gamma=0.001, c_form=0, w=10**(-8), max_it=500, info=0, ip=0): print('\n\tLPF predictor-corrector') # Algorithm in 4 steps: # 0..Input error checking # 1..Find the initial point with Mehrotra's method # 2..Predictor step # 3..Corrector step """ Input error checking & construction in a standard form """ if not (isinstance(A, np.ndarray) or isinstance(b, np.ndarray) or isinstance(c, np.ndarray)): info = 1 raise Exception('Inputs must be a numpy arrays: INFO {}'.format(info)) if c_form == 0: # Construction in a standard form [A | I] A, c = stdForm(A, c) r_A, c_A = A.shape if not np.linalg.matrix_rank(A) == r_A: # Remove ld rows: A = A[[ i for i in range(r_A) if not np.array_equal(np.linalg.qr(A)[1][i, :], np.zeros(c_A)) ], :] r_A = A.shape[0] # Update no. of rows """ Initial points: Initial infeasible positive (x,y,s) and initial gap g """ if ip == 0: (x, y, s) = sp(A, c, b) else: (x, y, s) = sp2(A, c, b) g = np.dot(c, x) - np.dot(y, b) if info == 0: print('\nInitial primal-dual point:\nx = {} \nlambda = {} \ns = {}'. format(x, y, s)) print('Dual initial gap: {}.\n'.format("%10.3f" % g)) # Check if (x, y, s) in neighborhood N_inf and define E: if not (x * s > gamma * np.dot(x, s) / c_A).all(): print("Initial point is not in N") E = lambda a: (s + a * s1) * (x + a * x1) - (gamma * np.dot( (s + a * s1), (x + a * x1))) / c_A # Function E: set of values in N_(gamma) #%% """ Predictor step """ '''Pure Newton's method with with normal equations: find the direction vector (y1, s1, x1)''' it = 0 # Num of iterations tm = term(it) # Define tollerance tm = inf u = [] # Construct list of info elements u.append([it, g, x, s, b - np.dot(A, x), c - np.dot(A.T, y) - s]) sig = [] while tm > w: if info == 0: print("\tIteration: {}\n".format(it + 1)) # Choose cp = 0 and compute the direction with augmented system (x1, y1, s1, rb, rc) = augm(A, b, c, x, y, s, 0) # Find the maximum alpha s.t the next iteration is in N_gamma v = np.arange(0, 1.0000, 0.0001) i = len(v) - 1 while i >= 0: if (E(v[i]) > 0).all(): t = v[i] # print('Largest step length:{}'.format("%10.3f"%t)) break else: i -= 1 mi = np.dot(x, s) / c_A # Duality measure mi_aff = np.dot( x + t * x1, s + t * s1) / c_A # Average value of the incremented vectors Sigma = (mi_aff / mi)**3 """ Corrector step: compute (x_k+1, lambda_k+1, s_k+1) """ (x1, y1, s1, rb, rc) = augm(A, b, c, x, y, s, Sigma) if info == 0: print( 'Search direction vectors: \n delta_x = {} \n delta_lambda = {} \n delta_s = {}.\n' .format(x1.round(decimals=3), x1.round(decimals=3), s1.round(decimals=3))) # Update x += t * x1 # Current x y += t * y1 # Current y s += t * s1 # Current s z = np.dot(c, x) # Current optimal solution g = z - np.dot(y, b) # Current gap it += 1 u.append([it, g, x.copy(), s.copy(), rb.copy(), rc.copy()]) sig.append(Sigma) # Termination elements tm = term(it, b, c, rb, rc, z, g) if it == max_it: raise TimeoutError("Iterations maxed out") if info == 0: print( '\nCurrent primal-dual point:\n x = {} \n lambda = {} \n s = {}.\n' .format(x.round(decimals=3), y.round(decimals=3), s.round(decimals=3))) print('Dual next gap: {}.\n'.format("%10.3f" % g)) #%% print_boxed("Found optimal solution of the problem at\n x* = {}.\n\n". format(x.round(decimals=3)) + "Dual gap: {}\n".format("%2.2e" % g) + "Optimal cost: {}\n".format("%10.3f" % z) + "Number of iteration: {}".format(it)) return x, s, u, sig
def longpathC(A, b, c, gamma=0.001, s_min=0.1, s_max=0.9, c_form=0, cp=0.6, w=0.005, max_iter=300): print('\n\tCOMPUTATION OF LPF ALGORITHM') """ Input error checking """ if not (isinstance(A, np.ndarray) or isinstance(b, np.ndarray) or isinstance(c, np.ndarray)): info = 1 raise Exception('Inputs must be a numpy arrays: INFO {}'.format(info)) # Construction in a standard form [A | I] if c_form == 0: A, c = stdForm(A, c) r_A, c_A = A.shape E = lambda a: (s + a * s1) * (x + a * x1) - (gamma * np.dot( (s + a * s1), (x + a * x1))) / c_A #Function E: set of values in N_(gamma) """ Check full rank matrix """ if not np.linalg.matrix_rank(A) == r_A: # Remove ld rows: A = A[[ i for i in range(r_A) if not np.array_equal(np.linalg.qr(A)[1][i, :], np.zeros(c_A)) ], :] r_A = A.shape[0] # Update no. of rows """ Initial points """ # Initial infeasible positive (x,y,s) and Initial gap g (x, y, s) = sp(A, c, b) g = np.dot(c, x) - np.dot(y, b) print('\nInitial primal-dual point:\nx = {} \nlambda = {} \ns = {}'.format( x, y, s)) print('Dual initial gap: {}.\n'.format("%10.3f" % g)) # Check if (x, y, s) in neighborhood N_inf: if (x * s > gamma * np.dot(x, s) / c_A).all(): print("Initial point is in N_inf(gamma), gamma = {}\n".format( "%10.6f" % gamma)) #%% """ search vector direction """ # Compute the search direction solving the matricial system # Instead of solving the std system matrix it is uses AUGMENT SYSTEM with CHOL approach it = 0 tm = term(it) u = [] u.append([it, g, x, s, b - np.dot(A, x), c - np.dot(A.T, y) - s]) # sigma = random.uniform(s_min, s_max) Choose centering parameter SIGMA_k in [sigma_min , sigma_max] while tm > 10**(-8): print("\tIteration: {}\n".format(it + 1), end='') S_inv = np.linalg.inv(np.diag(s)) W1 = S_inv * np.diag(x) # W1 = D = S^(-1)*X W2 = np.dot(A, W1) # W A*S^(-1)*X W = np.dot(W2, A.T) L = np.linalg.cholesky(W) # CHOLESKY for A* D^2 *A^T L_inv = np.linalg.inv(L) # RHS of the system rb = b - np.dot(A, x) rc = c - np.dot(A.T, y) - s rxs = -x * s + cp * (sum(x * s) / c_A) * np.ones( c_A) # Newton step toward x*s = sigma*mi B = rb + np.dot(W2, rc) - np.dot(np.dot(A, S_inv), rxs) #RHS of normal equation form z = np.dot(L_inv, B) # SEARCH DIRECTION: y1 = np.dot(L_inv.T, z) s1 = rc - np.dot(A.T, y1) x1 = np.dot(S_inv, rxs) - np.dot(W1, s1) print( 'Search direction vectors: \n delta_x = {} \n delta_lambda = {} \n delta_s = {}.\n' .format(x1.round(decimals=3), x1.round(decimals=3), s1.round(decimals=3))) #%% """ largest step length """ # We find the maximum alpha s. t the next iteration is in N_gamma v = np.arange(0, 0.999, 0.0001) i = len(v) - 1 while i >= 0: if (E(v[i]) > 0).all(): t = v[i] print('Largest step length:{}'.format("%10.3f" % t)) break else: i -= 1 # Increment the points and iteration x += t * x1 y += t * y1 s += t * s1 it += 1 if it == max_iter: print("Iterations maxed out") return x, s, u print('\nCurrent point:\n x = {} \n lambda = {} \n s = {}.\n'.format( x.round(decimals=3), y.round(decimals=3), s.round(decimals=3))) z = np.dot(c, x) g = z - np.dot(y, b) # Termination elements tm = term(it, b, c, rb, rc, z, g) u.append([it, g, x.copy(), s.copy(), rb.copy(), rc.copy()]) print('Dual next gap: {}.\n'.format("%10.3f" % g)) print_boxed("Found optimal solution of the problem at\n x* = {}.\n\n". format(x.round(decimals=3)) + "Dual gap: {}\n".format("%10.6f" % g) + "Optimal cost: {}\n".format("%10.3f" % z) + "Number of iteration: {}".format(it)) print("Centering parameter sigma:{}.\n".format("%10.3f" % cp)) return x, s, u
def affine2(A, b, c, c_form=0, w=10**(-8), max_iter=500): print('\n\tCOMPUTATION OF PRIMAL-DUAL AFFINE SCALING ALGORITHM') # Algorithm in 4 steps: # 0..Input error checking # 1..Find the initial point with Mehrotra's method # 2..obtain the search direction, # 3..find the largest step """ Input error checking """ if not (isinstance(A, np.ndarray) or isinstance(b, np.ndarray) or isinstance(c, np.ndarray)): raise Exception('Inputs must be a numpy arrays') # Construction in a standard form [A | I] if c_form == 0: A, c = stdForm(A, c) r_A, c_A = A.shape """ Check full rank matrix """ if not np.linalg.matrix_rank(A) == r_A: # Remove ld rows: A = A[[ i for i in range(r_A) if not np.array_equal(np.linalg.qr(A)[1][i, :], np.zeros(c_A)) ], :] r_A = A.shape[0] # Update no. of rows """ Initial points """ # Initial infeasible positive (x,y,s) and Initial gap g (x, y, s) = sp(A, c, b) g = np.dot(c, x) - np.dot(y, b) print('\nInitial primal-dual point:\n x = {} \n lambda = {} \n s = {}.\n'. format(x, y, s)) print('Dual initial gap: {}.\n'.format("%10.3f" % g)) #%% """ search vector direction """ it = 0 tm = term(it) u = [] u.append([it, g, x, s, b - np.dot(A, x), c - np.dot(A.T, y) - s]) while tm > w: print("\tIteration: {}\n".format(it)) # solve search direction with AUGMENTED SYSTEM X_inv = np.linalg.inv(np.diag(x)) W1 = X_inv * np.diag(s) # W1 = D = X^(-1)*S T = np.concatenate((np.zeros((r_A, r_A)), A), axis=1) U = np.concatenate((A.T, -W1), axis=1) V = np.concatenate((T, U), axis=0) rb = b - np.dot(A, x) rc = c - np.dot(A.T, y) - s rxs = -x * s # Newton step toward x*s r = np.hstack((rb, -np.dot(X_inv, rxs))) o = np.linalg.solve(V, r) y1 = o[:r_A] x1 = o[r_A:c_A + r_A] s1 = np.dot(X_inv, rxs) - np.dot(W1, x1) print( 'Search direction vectors: \n delta_x = {} \n delta_lambda = {} \n delta_s = {}.\n' .format(x1.round(decimals=3), y1.round(decimals=3), s1.round(decimals=3))) #%% """ largest step length """ # Largest step length T such that (x, s) + T (x1, s1) is positive m = min([(-x[i] / x1[i], i) for i in range(c_A) if x1[i] < 0], default=[1])[0] n = min([(-s[i] / s1[i], i) for i in range(c_A) if s1[i] < 0], default=[1])[0] T = (0.9) * min(m, n) # INCREMENT of the vectors and iterations x += min(T, 1) * x1 y += min(T, 1) * y1 s += min(T, 1) * s1 z = np.dot(c, x) # Current optimal solution g = z - np.dot(y, b) u.append([it, g, x.copy(), s.copy(), rb.copy(), rc.copy()]) # Termination elements tm = term(it, b, c, rb, rc, z, g) it += 1 if it == max_iter: raise TimeoutError("Iterations maxed out") print('Current point:\n x = {} \n lambda = {} \n s = {}.\n'.format( x, y, s)) print('Dual next gap: {}.\n'.format("%10.3f" % g)) print_boxed( "Found optimal solution of the problem at\n x* = {}.\n".format(x) + "Dual gap: {}\n".format("%10.6f" % g) + "Optimal cost: {}\n".format("%10.3f" % z) + "Number of iterations: {}".format(it)) return x, s, u
def mehrotra(A, b, c, c_form=0, w=10**(-8), max_it=500, info=0, ip=1): print('\n\tCOMPUTATION OF MEHROTRA ALGORITHM\n') # Algorithm in 4 steps: # 0..Input error checking # 1..Find the initial point with Mehrotra's method # 2..Predictor step # 3..Centering step # 4..Corrector step """ Input error checking & construction in a standard form """ if not (isinstance(A, np.ndarray) or isinstance(b, np.ndarray) or isinstance(c, np.ndarray)): raise Exception('Inputs must be a numpy arrays') if c_form == 0: A, c = stdForm(A, c) r_A, c_A = A.shape if not np.linalg.matrix_rank( A) == r_A: # Check full rank matrix:Remove ld rows: A = A[[ i for i in range(r_A) if not np.array_equal(np.linalg.qr(A)[1][i, :], np.zeros(c_A)) ], :] r_A = A.shape[0] # Update no. of rows """ Initial points: Initial infeasible positive (x,y,s) and initial gap g """ if ip == 0: (x, y, s) = sp(A, c, b) # MIP else: (x, y, s) = sp2(A, c, b) # STP1 g = np.dot(c, x) - np.dot(y, b) if info == 0: print('\nInitial primal-dual point:\nx = {} \nlambda = {} \ns = {}'. format(x, y, s)) print('Dual initial g: {}.\n'.format("%10.3f" % g)) #%% """ Predictor step: compute affine direction """ ''' Compute affine scaling direction solving Qs = R with system D^2 = S^{-1}*X with Q a large sparse matrix and R = [rb, rc, - x_0*s_0] ''' it = 0 # Num of iterations tm = term(it) # Tollerance in the cycle u = [] # Construct list of info elements sig = [] u.append([it, g, x, s, b - np.dot(A, x), c - np.dot(A.T, y) - s]) while tm > w: """ Pure Newton's method with with normal equations: find the direction vector (y1, s1, x1)""" S_inv = np.linalg.inv(np.diag(s)) # S^{-1} W1 = np.dot(S_inv, np.diag(x)) # W1 = D = S^(-1)*X W2 = np.dot(A, W1) # W2 A*S^(-1)*X W = np.dot(W2, A.T) L = np.linalg.cholesky(W) L_inv = np.linalg.inv(L) # RHS of the system, including the minus rb = b - np.dot(A, x) rc = c - np.dot(A.T, y) - s rxs = -x * s B = rb + np.dot(W2, rc) - np.dot(np.dot(A, S_inv), rxs) #RHS of normal equation form z = np.dot(L_inv, B) # SEARCH DIRECTION affine: y1 = np.dot(L_inv.T, z) s1 = rc - np.dot(A.T, y1) x1 = np.dot(S_inv, rxs) - np.dot(W1, s1) if info == 0: print("\n\tIteration: {}\n".format(it), end='') print( "\nPREDICTOR STEP:\nAffine direction:\n({}, {}, {})\n".format( x1, y1, s1)) #%% """ Centering step: compute search direction """ ''' Find alfa1_affine and alfa2_affine : maximum steplength along affine-scaling direction Find the minimum( x_{i}/x1_{i} , 1) and the minimum( s_{i}/s1_{i} , 1) ''' h = min([(-x[i] / x1[i], i) for i in range(c_A) if x1[i] < 0], default=[0])[0] k = min([(-s[i] / s1[i], i) for i in range(c_A) if s1[i] < 0], default=[0])[0] alfa1 = min(h, 1) alfa2 = min(k, 1) # Set the centering parameter to Sigma = (mi_aff/mi)^{3} mi = np.dot(x, s) / c_A # Duality measure mi_af = np.dot( x + alfa1 * x1, s + alfa2 * s1) / c_A # Average value of the incremented vectors Sigma = (mi_af / mi)**(3) # SECOND SEARCH DIRECTION Rxs = -x1 * s1 + Sigma * mi * np.ones( (c_A)) # RHS of the New system, including minus Rb = -np.dot(np.dot(A, S_inv), Rxs) # RHS of New normal equation form z = np.dot(L_inv, Rb) # SEARCH DIRECTION centering-orrector: y2 = np.dot(L_inv.T, z) s2 = -np.dot(A.T, y2) x2 = np.dot(S_inv, Rxs) - np.dot(W1, s2) if info == 0: print("Cc direction:\n({}, {}, {})\n".format(x2, y2, s2)) #%% """ Corrector step: compute (x_k+1, lambda_k+1, s_k+1) """ # The steplength without eta_k x2 += x1 s2 += s1 y2 += y1 H = min([(-x[i] / x2[i], i) for i in range(c_A) if x2[i] < 0], default=[0])[0] K = min([(-s[i] / s2[i], i) for i in range(c_A) if s2[i] < 0], default=[0])[0] Alfa1 = min(0.99 * H, 1) Alfa2 = min(0.99 * K, 1) # Update x += Alfa1 * x2 # Current x y += Alfa2 * y2 # Current y s += Alfa2 * s2 # Current s z = np.dot(c, x) # Current optimal solution g = z - np.dot(y, b) # Current gap it += 1 u.append([it, g, x.copy(), s.copy(), rb.copy(), rc.copy()]) sig.append([Sigma]) # Termination elements tm = term(it, b, c, rb, rc, z, g) if it == max_it: raise TimeoutError("Iterations maxed out") if info == 0: print('CORRECTOR STEP:\nCurrent primal-dual point: \n x = ', x, '\nlambda = ', y, '\n s = ', s) print('Current g: {}\n'.format("%.3f" % g)) #%% print_boxed( "Found optimal solution of the standard problem at\n x* = {}.\n\n". format(x) + "Dual gap: {}\n".format("%2.2e" % g) + "Optimal cost: {}\n".format("%10.3f" % z) + "Number of iteration: {}".format(it)) return x, s, u, sig
def affine(A, b, c, c_form = 0, w = 10**(-8), max_it = 500, info = 0, ip = 0): print('\n\tCOMPUTATION OF PRIMAL-DUAL AFFINE SCALING ALGORITHM') # Algorithm in 4 steps: # 0..Input error checking # 1..Find the initial point with Mehrotra's method # 2..obtain the search direction # 3..find the largest step """ Input error checking & construction in a standard form """ if not (isinstance(A, np.ndarray) or isinstance(b, np.ndarray) or isinstance(c, np.ndarray)): raise Exception('Inputs must be a numpy arrays') if c_form == 0: A, c = stdForm(A, c) r_A, c_A = A.shape if not np.linalg.matrix_rank(A) == r_A: # Check full rank matrix: Remove ld rows A = A[[i for i in range(r_A) if not np.array_equal(np.linalg.qr(A)[1][i, :], np.zeros(c_A))], :] r_A = A.shape[0] # Update no. of rows """ Initial points: Initial infeasible positive (x,y,s) and initial gap g """ if ip == 0: (x, y, s) = sp(A, c, b) else: (x, y, s) = sp2(A, c, b) g = np.dot(c,x) - np.dot(y,b) if info == 0: print('\nInitial primal-dual point:\n x = {} \n lambda = {} \n s = {}.\n'.format(x, y, s)) print('Dual initial gap: {}.\n'.format("%10.3f"%g)) #%% """ Search vector direction """ it = 0 # Num of iterations tm = term(it) # Tollerance in the cycle u = [] # Construct list of info elements u.append([it, g, x, s, b - np.dot(A,x), c - np.dot(A.T, y) - s]) while tm > w: """ Pure Newton's method with with normal equations: find the direction vector (y1, s1, x1)""" S_inv = np.linalg.inv(np.diag(s)) W1 = S_inv*np.diag(x) # W1 = D = S^(-1)*X W2 = np.dot(A, W1) # W A*S^(-1)*X W = np.dot(W2, A.T) L = np.linalg.cholesky(W) # CHOLESKY for A* D^2 *A^T L_inv = np.linalg.inv(L) # RHS of the system rb = b - np.dot(A, x) rc = c - np.dot(A.T, y) - s rxs = - x*s # Newton step toward x*s = 0 B = rb + np.dot(W2, rc) - np.dot(np.dot(A, S_inv), rxs) #RHS of normal equation form z = np.dot(L_inv, B) # SEARCH DIRECTION: y1 = np.dot(L_inv.T, z) s1 = rc - np.dot(A.T, y1) x1 = np.dot(S_inv, rxs) - np.dot(W1,s1) if info == 0: print("\tIteration: {}\n".format(it)) print('Search direction vectors: \n delta_x = {} \n delta_lambda = {} \n delta_s = {}.\n'.format(x1.round(decimals = 3),y1.round(decimals = 3),s1.round(decimals = 3))) """ Compute the largest step length & increment of the points and the iteration""" # Largest step length T such that (x, s) + T (x1, s1) is positive m = min([(-x[i] / x1[i], i) for i in range(c_A) if x1[i] < 0], default = [1])[0] n = min([(-s[i] / s1[i], i) for i in range(c_A) if s1[i] < 0], default = [1])[0] T = (0.9)*min(m, n) # Update step x += min(T,1)*x1 # Current x y += min(T,1)*y1 # Current y s += min(T,1)*s1 # Current s rb = b - np.dot(A, x) rc = c - np.dot(A.T, y) - s z = np.dot(c, x) # Current optimal solution g = np.abs(z - np.dot(y, b))# Current gap it += 1 u.append([it, g.copy(), x.copy(), s.copy(), rb.copy(), rc.copy()]) # Termination elements m, n, q = term(it, b, c, rb, rc, z, g) tm = max(m, n, q) if it == max_it: raise TimeoutError("Iterations maxed out") if info == 0: print('Current point:\n x = {} \n lambda = {} \n s = {}.\n'.format(x, y, s)) print('Dual next gap: {}.\n'.format("%10.3f"%g)) #%% print_boxed("Found optimal solution of the problem at\n x* = {}.\n".format(x) + "Dual gap: {}\n".format("%10.6f"%g) + "Optimal cost: {}\n".format("%.8E" %z) + "Number of iterations: {}".format(it)) return x, s, u
def mehrotra2(A, b, c, c_form=0, w=10**(-8), max_it=500, info=0, ip=0): print('\n\tCOMPUTATION OF MEHROTRA ALGORITHMwith Augmented system\n') # Algorithm in 4 steps: # 0..Input error checking # 1..Find the initial point with Mehrotra's method # 2..Predictor step # 3..Centering step # 4..Corrector step """ Input error checking & construction in a standard form """ if not (isinstance(A, np.ndarray) or isinstance(b, np.ndarray) or isinstance(c, np.ndarray)): raise Exception('Inputs must be a numpy arrays') if c_form == 0: A, c = stdForm(A, c) r_A, c_A = A.shape if not np.linalg.matrix_rank( A) == r_A: # Check full rank matrix:Remove ld rows: A = A[[ i for i in range(r_A) if not np.array_equal(np.linalg.qr(A)[1][i, :], np.zeros(c_A)) ], :] r_A = A.shape[0] # Update no. of rows """ Initial points: Initial infeasible positive (x,y,s) and initial gap g """ if ip == 0: (x, y, s) = sp(A, c, b) else: (x, y, s) = sp2(A, c, b) g = np.dot(c, x) - np.dot(y, b) if info == 0: print('\nInitial primal-dual point:\nx = {} \nlambda = {} \ns = {}'. format(x, y, s)) print('Dual initial g: {}.\n'.format("%10.3f" % g)) #%% """ Predictor step: compute affine direction """ ''' Compute affine scaling direction solving Qs = R with an augmented system D^2 = S^{-1}*X with Q a large sparse matrix and R = [rb, rc, - x_0*s_0] ''' it = 0 # Num of iterations tm = term(it) # Tollerance in the cycle u = [] # Construct list of info elements sig = [] u.append([it, g, x, s, b - np.dot(A, x), c - np.dot(A.T, y) - s]) while tm > w: if info == 0: print("\n\tIteration: {}\n".format(it), end='') X_inv = np.linalg.inv(np.diag(x)) W1 = X_inv * np.diag(s) # W1 = X^(-1)*S T = np.concatenate((np.zeros((r_A, r_A)), A), axis=1) U = np.concatenate((A.T, -W1), axis=1) V = np.concatenate((T, U), axis=0) # RHS of the system, including the minus rb = b - np.dot(A, x) rc = c - np.dot(A.T, y) - s rxs = -x * s r = np.hstack((rb, rc - np.dot(X_inv, rxs))) o = np.linalg.solve(V, r) # SEARCH DIRECTION affine: y1 = o[:r_A] x1 = o[r_A:c_A + r_A] s1 = np.dot(X_inv, rxs) - np.dot(W1, x1) if info == 0: print( "\nPREDICTOR STEP:\nAffine direction:\n({}, {}, {})\n".format( x1, y1, s1)) #%% """ Centering step: compute search direction """ # Find alfa1_affine and alfa2_affine : maximum steplength along affine-scaling direction # Find the minimum( x_{i}/x1_{i} , 1) and the minimum( s_{i}/s1_{i} , 1) h = min([(-x[i] / x1[i], i) for i in range(c_A) if x1[i] < 0], default=[0])[0] k = min([(-s[i] / s1[i], i) for i in range(c_A) if s1[i] < 0], default=[0])[0] alfa1 = min(h, 1) alfa2 = min(k, 1) # Set the centering parameter to Sigma = (mi_aff/mi)^{3} mi = np.dot(x, s) / c_A # Duality measure mi_af = np.dot( x + alfa1 * x1, s + alfa2 * s1) / c_A # Average value of the incremented vectors Sigma = (mi_af / mi)**(3) # SECOND SEARCH DIRECTION Rxs = -x1 * s1 + Sigma * mi * np.ones( (c_A)) # RHS of the New system, including minus r = np.hstack((np.zeros(r_A), -np.dot(X_inv, Rxs))) o = np.linalg.solve(V, r) # SEARCH DIRECTION centering-corrector: y2 = o[:r_A] x2 = o[r_A:c_A + r_A] s2 = np.dot(X_inv, Rxs) - np.dot(W1, x2) if info == 0: print("\nPREDICTOR STEP:\nCC direction:\n({}, {}, {})\n".format( x2, y2, s2)) #%% """ Corrector step: compute (x_k+1, lambda_k+1, s_k+1) """ # The steplength without eta_k x2 += x1 s2 += s1 y2 += y1 H = min([(-x[i] / x2[i], i) for i in range(c_A) if x2[i] < 0], default=[0])[0] K = min([(-s[i] / s2[i], i) for i in range(c_A) if s2[i] < 0], default=[0])[0] Alfa1 = min(0.99 * H, 1) Alfa2 = min(0.99 * K, 1) # Compute the final update , using sol2 and Alfa_i x += Alfa1 * x2 y += Alfa2 * y2 s += Alfa2 * s2 it += 1 if it == max_it: return x, s, u, sig raise TimeoutError("Iterations maxed out") # Dual gap c^{T}*x - b^{T}*y = x*s z = np.dot(c, x) g = np.dot(x, s) g1 = z - np.dot(y, b) u.append([it, g, x.copy(), s.copy(), rb.copy(), rc.copy()]) sig.append([Sigma]) # Termination elements m, n, q = term(it, b, c, rb, rc, z, g) tm = max(m, n, q) if info == 0: print('Tollerance: {}.\n'.format("%10.3f" % tm)) print('CORRECTOR STEP:\nCurrent primal-dual point: \n x = ', x, '\nlambda = ', y, '\n s = ', s) print('Current g: {}\nCurrent g1: {}\n'.format( "%.3f" % g, "%.3f" % g1)) print_boxed( "Found optimal solution of the standard problem at\n x* = {}.\n\n". format(x) + "Dual gap: {}\n".format("%2.2e" % g) + "Optimal cost: {}\n".format("%2.8E" % z) + "Number of iteration: {}".format(it)) return x, s, u, sig