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
def test_dictionary_to_permutation(): permutation = {0: 1, 1: 2, 2: 0} expected = np.mat([[0, 1, 0], [0, 0, 1], [1, 0, 0]]) actual = dictionary_to_permutation(permutation) assert np.all(expected == actual)