def test_row_echelon(): A = np.array([[2., 1, -1, 8], [-3, -1, 2, -11], [-2, 1, 2, -3]]) R, p = to_row_echelon(A) assert np.all(R[:, 0] == np.array([2, 0, 0])) assert np.all(R[1:, 1] == np.array([1 / 2, 0])) assert np.all(R[2:, 2] == np.array([-1])) A = np.array([[0., 1, 0, 0], [1, 0, 0, 0], [0, 0, 0, 1]]) R, p = to_row_echelon(A) expected = np.array([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 0, 1]]) assert np.all(R == expected) A = np.array([[1., 0, 0, 0], [0, 0, 0, 1], [1, 0, 1, 1]]) R, p = to_row_echelon(A) expected = np.array([[1, 0, 0, 0], [0, 0, 1, 1], [0, 0, 0, 1]]) assert np.all(R == expected) A = np.array([[1., 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 2]]) R, p = to_row_echelon(A) expected = np.array([[1, 1, 1, 1], [0, 0, 0, 1], [0, 0, 0, 0]]) assert np.all(R == expected)
def cvxopt_solver(G, h, A, b, c, n): # cvxopt doesn't allow redundant constraints in the linear program Ax = b, # so we need to do some preprocessing to find and remove any linearly # dependent rows in the augmented matrix [A | b]. # # First we do Gaussian elimination to put the augmented matrix into row # echelon (reduced row echelon form is not necessary). Since b comes as a # numpy array (that is, a row vector), we need to convert it to a numpy # matrix before transposing it (that is, to a column vector). b = np.mat(b).T A_b = np.hstack((A, b)) A_b, permutation = to_row_echelon(np.hstack((A, b))) # Next, we apply the inverse of the permutation applied to compute the row # echelon form. P = dictionary_to_permutation(permutation) A_b = P.I * A_b # Trim any rows that are all zeros. The call to np.any returns an array of # Booleans that correspond to whether a row in A_b is all zeros. Indexing # A_b by an array of Booleans acts as a selector. We need to use np.asarray # in order for indexing to work, since it expects a row vector instead of a # column vector. A_b = A_b[np.any(np.asarray(A_b) != 0, axis=1)] # Split the augmented matrix back into a matrix and a vector. A, b = A_b[:, :-1], A_b[:, -1] # Apply the linear programming solver; cvxopt requires that these are all # of a special type of cvx-specific matrix. G, h, A, b, c = (cvx_matrix(M) for M in (G, h, A, b, c)) solution = cvx_solvers.lp(c, G, h, A, b) if solution['status'] == 'optimal': return True, solution['x'] # TODO status could be 'unknown' here, but we're currently ignoring that return False, None