def test_gurobipy_return_same_result_as_scipy(): c, A, b = example_1d() result_gurobi = solvers.lpsolve(c, A, b, solver='gurobi') result_scipy = solvers.lpsolve(c, A, b, solver='scipy') nt.assert_equal(result_scipy['status'], result_gurobi['status']) nt.assert_almost_equal(result_scipy['x'][0], result_gurobi['x'][0]) nt.assert_almost_equal(result_scipy['fun'], result_gurobi['fun'])
def test_request_glpk_after_changing_default_to_scipy(): c, A, b = example_1d() have_glpk = is_glpk_present() if not have_glpk: return assert solvers.default_solver != 'scipy' solvers.default_solver = 'scipy' solvers.lpsolve(c, A, b, solver='glpk')
def test_lpsolve_solver_selection_glpk_absent(): c, A, b = example_1d() have_glpk = is_glpk_present() # skip if GLPK imports if have_glpk: log.info('Skipping GLPK failure test, ' 'because GLPK is present.') return with nt.assert_raises(RuntimeError): solvers.lpsolve(c, A, b, solver='glpk')
def test_lpsolve_solver_selection_glpk_absent(): c, A, b = example_1d() have_glpk = is_glpk_present() # skip if GLPK imports if have_glpk: log.info( 'Skipping GLPK failure test, ' 'because GLPK is present.') return with nt.assert_raises(RuntimeError): solvers.lpsolve(c, A, b, solver='glpk')
def test_lpsolve_solver_selection_scipy(): # should always work, because `polytope` requires `scipy` c, A, b = example_1d() r_ = np.array([-1.0]) # call directly to isolate from selection within `lpsolve` r = solvers._solve_lp_using_scipy(c, A, b) assert r['x'] == r_, r['x'] r = solvers.lpsolve(c, A, b, solver='scipy') assert r['x'] == r_, r['x']
def test_lpsolve_solver_selection_glpk_present(): c, A, b = example_1d() have_glpk = is_glpk_present() # skip if GLPK fails to import if not have_glpk: log.info('Skipping GLPK test of `lpsolve` ' 'because GLPK failed to import, ' 'so assume not installed.') return r = solvers.lpsolve(c, A, b, solver='glpk') assert r['x'] == np.array([-1.0]), r['x']
def test_lpsolve(): # Ensure same API for both `scipy` and `cvxopt`. # Ensured by the different testing configurations. # Could change `polytope.polytope.default_solver` to # achieve the same result, when `cvxopt.glpk` is present. # # 2-D example c = np.array([1, 1], dtype=float) A = np.array([[-1, 0], [0, -1]], dtype=float) b = np.array([1, 1], dtype=float) res = solvers.lpsolve(c, A, b) x = res['x'] assert x.ndim == 1, x.ndim assert x.shape == (2, ), x.shape # # 1-D example c, A, b = example_1d() res = solvers.lpsolve(c, A, b) x = res['x'] assert x.ndim == 1, x.ndim assert x.shape == (1, ), x.shape
def test_lpsolve_solver_selection_glpk_present(): c, A, b = example_1d() have_glpk = is_glpk_present() # skip if GLPK fails to import if not have_glpk: log.info( 'Skipping GLPK test of `lpsolve` ' 'because GLPK failed to import, ' 'so assume not installed.') return r = solvers.lpsolve(c, A, b, solver='glpk') assert r['x'] == np.array([-1.0]), r['x']
def test_lpsolve(): # Ensure same API for both `scipy` and `cvxopt`. # Ensured by the different testing configurations. # Could change `polytope.polytope.default_solver` to # achieve the same result, when `cvxopt.glpk` is present. # # 2-D example c = np.array([1, 1], dtype=float) A = np.array([[-1, 0], [0, -1]], dtype=float) b = np.array([1, 1], dtype=float) res = solvers.lpsolve(c, A, b) x = res['x'] assert x.ndim == 1, x.ndim assert x.shape == (2,), x.shape # # 1-D example c, A, b = example_1d() res = solvers.lpsolve(c, A, b) x = res['x'] assert x.ndim == 1, x.ndim assert x.shape == (1,), x.shape
def shoot(C, D, b, maxiter=1000, abs_tol=1e-7): """Return random equality set of P that projects on a projection facet. Returns randomly selected equality set E_0 of P such that the projection of the equality set is a facet of the projection. @param C: Matrix defining the polytope Cx+Dy <= b @param D: Matrix defining the polytope Cx+Dy <= b @param b: Vector defining the polytope Cx+Dy <= b @return: `E_0,af,bf`: Equality set and affine hull """ d = C.shape[1] k = D.shape[1] iter = 0 while True: if iter > maxiter: raise Exception("shoot: could not find starting equality set") gamma = np.random.rand(d) - 0.5 c = np.zeros(k + 1) c[0] = -1 G = np.hstack([np.array([np.dot(C, gamma)]).T, D]) sol = solvers.lpsolve(c, G, b, solver='glpk') opt_sol = np.array(sol['x']).flatten() opt_dual = np.array(sol['z']).flatten() r_opt = opt_sol[0] y_opt = np.array(opt_sol[range(1, len(opt_sol))]).flatten() x_opt = r_opt * gamma E_0 = np.nonzero( np.abs(np.dot(C, x_opt) + np.dot(D, y_opt) - b) < abs_tol)[0] DE0 = D[E_0, :] CE0 = C[E_0, :] b0 = b[E_0] if rank(np.dot(null_space(DE0.T).T, CE0)) == 1: break iter += 1 af, bf = proj_aff(CE0, DE0, b0, abs_tol=abs_tol) if is_dual_degenerate(c, G, b, None, None, opt_sol, opt_dual, abs_tol=abs_tol): E_0 = unique_equalityset(C, D, b, af, bf, abs_tol=abs_tol) af, bf = proj_aff(C[E_0, :], D[E_0, :], b[E_0]) if len(bf) > 1: raise Exception("shoot: wrong dimension of affine hull") return E_0, af.flatten(), bf
def shoot(C, D, b, maxiter=1000, abs_tol=1e-7): """Return random equality set of P that projects on a projection facet. Returns randomly selected equality set E_0 of P such that the projection of the equality set is a facet of the projection. @param C: Matrix defining the polytope Cx+Dy <= b @param D: Matrix defining the polytope Cx+Dy <= b @param b: Vector defining the polytope Cx+Dy <= b @return: `E_0,af,bf`: Equality set and affine hull """ d = C.shape[1] k = D.shape[1] iter = 0 while True: if iter > maxiter: raise Exception( "shoot: could not find starting equality set") gamma = np.random.rand(d) - 0.5 c = np.zeros(k + 1) c[0] = -1 G = np.hstack([np.array([np.dot(C, gamma)]).T, D]) sol = solvers.lpsolve(c, G, b, solver='glpk') opt_sol = np.array(sol['x']).flatten() opt_dual = np.array(sol['z']).flatten() r_opt = opt_sol[0] y_opt = np.array(opt_sol[range(1, len(opt_sol))]).flatten() x_opt = r_opt * gamma E_0 = np.nonzero( np.abs(np.dot(C, x_opt) + np.dot(D, y_opt) - b) < abs_tol)[0] DE0 = D[E_0, :] CE0 = C[E_0, :] b0 = b[E_0] if rank(np.dot(null_space(DE0.T).T, CE0)) == 1: break iter += 1 af, bf = proj_aff(CE0, DE0, b0, abs_tol=abs_tol) if is_dual_degenerate(c, G, b, None, None, opt_sol, opt_dual, abs_tol=abs_tol): E_0 = unique_equalityset(C, D, b, af, bf, abs_tol=abs_tol) af, bf = proj_aff(C[E_0, :], D[E_0, :], b[E_0]) if len(bf) > 1: raise Exception("shoot: wrong dimension of affine hull") return E_0, af.flatten(), bf
def unique_equalityset2(C, D, b, opt_sol, abs_tol=1e-7): A = np.hstack([C, D]) E0 = np.nonzero(np.abs(np.dot(A, opt_sol) - b) < abs_tol)[0] af, bf = proj_aff(C[E0, :], D[E0, :], b[E0], expected_dim=1) # stack ineq = np.hstack([af, np.zeros(D.shape[1])]) G = np.vstack([A, np.vstack([ineq, -ineq])]) h = np.hstack([b, np.hstack([bf, -bf])]) # shape m = G.shape[0] n = G.shape[1] # ht e = 1e-3 v = np.vstack([np.zeros([1, n]), np.eye(n)]).T v = v - np.array([np.mean(v, axis=1)]).T v = v * e ht = h + np.amin(-np.dot(G, v), axis=1) # stack H1 = np.hstack([G, -np.eye(m)]) H2 = np.hstack([G, np.zeros([m, m])]) H3 = np.hstack([np.zeros([m, n]), -np.eye(m)]) H = np.vstack([H1, np.vstack([H2, H3])]) h = np.hstack([ht, np.hstack([h, np.zeros(m)])]) c = np.hstack([np.zeros(n), np.ones(m)]) sol = solvers.lpsolve(c, H, h, solver='glpk') if not sol['status'] == "optimal": raise Exception( "unique_equalityset: LP returned status " + str(sol['status'])) opt_sol2 = np.array(sol['x']).flatten() x = opt_sol2[range(0, n)] s = opt_sol2[range(n, len(opt_sol2))] E = np.nonzero(s > abs_tol)[0] print(E) E = np.sort(E[np.nonzero(E < C.shape[0])]) # Check that they define the same projection at, bt = proj_aff(C[E, :], D[E, :], b[E]) if bt.size != 1 or np.sum(np.abs(at - af)) + np.abs(bt - bf) > abs_tol: raise Exception("unique_equalityset2: affine hulls not the same") return E
def unique_equalityset2(C, D, b, opt_sol, abs_tol=1e-7): A = np.hstack([C, D]) E0 = np.nonzero(np.abs(np.dot(A, opt_sol) - b) < abs_tol)[0] af, bf = proj_aff(C[E0, :], D[E0, :], b[E0], expected_dim=1) # stack ineq = np.hstack([af, np.zeros(D.shape[1])]) G = np.vstack([A, np.vstack([ineq, -ineq])]) h = np.hstack([b, np.hstack([bf, -bf])]) # shape m = G.shape[0] n = G.shape[1] # ht e = 1e-3 v = np.vstack([np.zeros([1, n]), np.eye(n)]).T v = v - np.array([np.mean(v, axis=1)]).T v = v * e ht = h + np.amin(-np.dot(G, v), axis=1) # stack H1 = np.hstack([G, -np.eye(m)]) H2 = np.hstack([G, np.zeros([m, m])]) H3 = np.hstack([np.zeros([m, n]), -np.eye(m)]) H = np.vstack([H1, np.vstack([H2, H3])]) h = np.hstack([ht, np.hstack([h, np.zeros(m)])]) c = np.hstack([np.zeros(n), np.ones(m)]) sol = solvers.lpsolve(c, H, h, solver='glpk') if not sol['status'] == "optimal": raise Exception("unique_equalityset: LP returned status " + str(sol['status'])) opt_sol2 = np.array(sol['x']).flatten() x = opt_sol2[range(0, n)] s = opt_sol2[range(n, len(opt_sol2))] E = np.nonzero(s > abs_tol)[0] print(E) E = np.sort(E[np.nonzero(E < C.shape[0])]) # Check that they define the same projection at, bt = proj_aff(C[E, :], D[E, :], b[E]) if bt.size != 1 or np.sum(np.abs(at - af)) + np.abs(bt - bf) > abs_tol: raise Exception("unique_equalityset2: affine hulls not the same") return E
def cheby_center(C, D, b): """Calculate Chebyshev center for the polytope `C x + D y <= b`. Input: `C, D, b`: Polytope parameters Output: `x_0, y_0`: The chebyshev centra `boolean`: True if a point could be found, False otherwise. """ d = C.shape[1] k = D.shape[1] A = np.hstack([C, D]) dim = np.shape(A)[1] c = -np.r_[np.zeros(dim), 1] norm2 = np.sqrt(np.sum(A * A, axis=1)) G = np.c_[A, norm2] sol = solvers.lpsolve(c, G, h=b, solver='glpk') if sol['status'] == "optimal": opt = np.array(sol['x'][0:-1]).flatten() return opt[range(0, d)], opt[range(d, d + k)], True else: return np.zeros(d), np.zeros(k), False
def cheby_center(C, D, b): """Calculate Chebyshev center for the polytope `C x + D y <= b`. Input: `C, D, b`: Polytope parameters Output: `x_0, y_0`: The chebyshev centra `boolean`: True if a point could be found, False otherwise. """ d = C.shape[1] k = D.shape[1] A = np.hstack([C, D]) dim = np.shape(A)[1] c = - np.r_[np.zeros(dim), 1] norm2 = np.sqrt(np.sum(A * A, axis=1)) G = np.c_[A, norm2] sol = solvers.lpsolve(c, G, h=b, solver='glpk') if sol['status'] == "optimal": opt = np.array(sol['x'][0:-1]).flatten() return opt[range(0, d)], opt[range(d, d + k)], True else: return np.zeros(d), np.zeros(k), False
def esp(CC, DD, bb, centered=False, abs_tol=1e-10, verbose=0): """Project polytope [C D] x <= b onto C coordinates. Projects the polytope [C D] x <= b onto the coordinates that correspond to C. The projection of the polytope P = {[C D]x <= b} where C is M x D and D is M x K is defined as proj(P) = {x in R^d | exist y in R^k s.t Cx + Dy < b} """ if 'glpk' in solvers.installed_solvers: raise Exception( "projection_esp error:" " Equality set projection requires `cvxopt.glpk` to run.") # Remove zero columns and rows nonzerorows = np.nonzero( np.sum(np.abs(np.hstack([CC, DD])), axis=1) > abs_tol)[0] nonzeroxcols = np.nonzero(np.sum(np.abs(CC), axis=0) > abs_tol)[0] nonzeroycols = np.nonzero(np.sum(np.abs(DD), axis=0) > abs_tol)[0] C = CC[nonzerorows, :].copy() D = DD[nonzerorows, :].copy() C = C[:, nonzeroxcols] D = D[:, nonzeroycols] b = bb[nonzerorows].copy() # Make sure origo is inside polytope if not centered: xc0, yc0, trans = cheby_center(C, D, b) if trans: b = b - np.dot(C, xc0).flatten() - np.dot(D, yc0).flatten() else: b = b else: trans = False d = C.shape[1] k = D.shape[1] if verbose > 0: print("Projecting from dim " + str(d + k) + " to " + str(d)) if k == 0: # Not projecting return C, bb, [] if d == 1: # Projection to 1D c = np.zeros(d + k) c[0] = 1 G = np.hstack([C, D]) sol = solvers.lpsolve(c, G, b, solver='glpk') if sol['status'] != "optimal": raise Exception( "esp: projection to 1D is not full-dimensional, " "LP returned status " + str(sol['status'])) min_sol = np.array(sol['x']).flatten() min_dual_sol = np.array(sol['z']).flatten() sol = solvers.lpsolve(-c, G, b, solver='glpk') if sol['status'] != "optimal": raise Exception( "esp: projection to 1D is not full-dimensional, " + "LP returned status " + str(sol['status'])) max_sol = np.array(sol['x']).flatten() max_dual_sol = np.array(sol['z']).flatten() # min, max x_min = min_sol[0] x_max = max_sol[0] y_min = min_sol[range(1, k + 1)] y_max = max_sol[range(1, k + 1)] if is_dual_degenerate(c, G, b, None, None, min_sol, min_dual_sol): # Min case, relax constraint a little to avoid infeasibility E_min = unique_equalityset( C, D, b, np.array([1.]), x_min + abs_tol / 3, abs_tol=abs_tol) else: E_min = np.nonzero(np.abs(np.dot(G, min_sol) - b) < abs_tol)[0] if is_dual_degenerate(c, G, b, None, None, max_sol, max_dual_sol): # Max case, relax constraint a little to avoid infeasibility E_max = unique_equalityset( C, D, b, np.array([1.]), x_max - abs_tol / 3, abs_tol=abs_tol) else: E_max = np.nonzero(np.abs(np.dot(G, max_sol) - b) < abs_tol)[0] G = np.array([[1.], [-1.]]) g = np.array([x_max, -x_min]) # Relocate if trans: g = g + np.dot(G, xc0) # Return zero cols/rows E_max = nonzerorows[E_max] E_min = nonzerorows[E_min] if verbose > 0: print( "Returning projection from dim " + str(d + k) + " to dim 1 \n") return G, g, [E_max, E_min] E = [] L = [] E_0, af, bf = shoot(C, D, b, abs_tol=abs_tol) ridge_list = ridge(C, D, b, E_0, af, bf, abs_tol=abs_tol, verbose=verbose) for i in range(len(ridge_list)): r = ridge_list[i] L.append(Ridge_Facet(r.E_r, r.ar, r.br, E_0, af, bf)) G = af.T g = bf if verbose > 0: print("\nStarting eq set " + str(E_0) + "\nStarting ridges ") for rr in L: print(str(rr.E_r)) E.append(E_0) while len(L) > 0: rid_fac1 = L[0] if verbose > 0: print("\nLooking for neighbors to " + str(rid_fac1.E_0) + " and " + str(rid_fac1.E_r) + " ..") E_adj, a_adj, b_adj = adjacent(C, D, b, rid_fac1, abs_tol=abs_tol) if verbose > 0: print("found neighbor " + str(E_adj) + ". \n\nLooking for ridges of neighbor..") ridge_list = ridge( C, D, b, E_adj, a_adj, b_adj, abs_tol=abs_tol, verbose=verbose) if verbose > 0: print("found " + str(len(ridge_list)) + " ridges\n") found_org = False for i in range(len(ridge_list)): r = ridge_list[i] E_r = r.E_r ar = r.ar br = r.br found = False for j in range(len(L)): rid_fac2 = L[j] A_r = rid_fac2.E_r if len(A_r) != len(E_r): continue t1 = np.sort(np.array(A_r)) t2 = np.sort(np.array(E_r)) if np.sum(np.abs(t1 - t2)) < abs_tol: found = True break if found: if verbose > 0: print("Ridge " + str(E_r) + " already visited, removing from L..") if rid_fac2 == rid_fac1: found_org = True L.remove(rid_fac2) else: if verbose > 0: print("Adding ridge-facet " + str(E_adj) + " " + str(E_r) + "") L.append(Ridge_Facet(E_r, ar, br, E_adj, a_adj, b_adj)) if not found_org: print("Expected ridge " + str(rid_fac1.E_r)) print("but got ridges ") for rid in ridge_list: print(rid.E_r) raise Exception( "esp: ridge did not return neighboring ridge as expected") G = np.vstack([G, a_adj]) g = np.hstack([g, b_adj]) E.append(E_adj) # Restore center if trans: g = g + np.dot(G, xc0) # Return zero rows for Ef in E: Ef = nonzerorows[Ef] return G, g, E
def esp(CC, DD, bb, centered=False, abs_tol=1e-10, verbose=0): """Project polytope [C D] x <= b onto C coordinates. Projects the polytope [C D] x <= b onto the coordinates that correspond to C. The projection of the polytope P = {[C D]x <= b} where C is M x D and D is M x K is defined as proj(P) = {x in R^d | exist y in R^k s.t Cx + Dy < b} """ if 'glpk' in solvers.installed_solvers: raise Exception( "projection_esp error:" " Equality set projection requires `cvxopt.glpk` to run.") # Remove zero columns and rows nonzerorows = np.nonzero( np.sum(np.abs(np.hstack([CC, DD])), axis=1) > abs_tol)[0] nonzeroxcols = np.nonzero(np.sum(np.abs(CC), axis=0) > abs_tol)[0] nonzeroycols = np.nonzero(np.sum(np.abs(DD), axis=0) > abs_tol)[0] C = CC[nonzerorows, :].copy() D = DD[nonzerorows, :].copy() C = C[:, nonzeroxcols] D = D[:, nonzeroycols] b = bb[nonzerorows].copy() # Make sure origo is inside polytope if not centered: xc0, yc0, trans = cheby_center(C, D, b) if trans: b = b - np.dot(C, xc0).flatten() - np.dot(D, yc0).flatten() else: b = b else: trans = False d = C.shape[1] k = D.shape[1] if verbose > 0: print("Projecting from dim " + str(d + k) + " to " + str(d)) if k == 0: # Not projecting return C, bb, [] if d == 1: # Projection to 1D c = np.zeros(d + k) c[0] = 1 G = np.hstack([C, D]) sol = solvers.lpsolve(c, G, b, solver='glpk') if sol['status'] != "optimal": raise Exception("esp: projection to 1D is not full-dimensional, " "LP returned status " + str(sol['status'])) min_sol = np.array(sol['x']).flatten() min_dual_sol = np.array(sol['z']).flatten() sol = solvers.lpsolve(-c, G, b, solver='glpk') if sol['status'] != "optimal": raise Exception("esp: projection to 1D is not full-dimensional, " + "LP returned status " + str(sol['status'])) max_sol = np.array(sol['x']).flatten() max_dual_sol = np.array(sol['z']).flatten() # min, max x_min = min_sol[0] x_max = max_sol[0] y_min = min_sol[range(1, k + 1)] y_max = max_sol[range(1, k + 1)] if is_dual_degenerate(c, G, b, None, None, min_sol, min_dual_sol): # Min case, relax constraint a little to avoid infeasibility E_min = unique_equalityset(C, D, b, np.array([1.]), x_min + abs_tol / 3, abs_tol=abs_tol) else: E_min = np.nonzero(np.abs(np.dot(G, min_sol) - b) < abs_tol)[0] if is_dual_degenerate(c, G, b, None, None, max_sol, max_dual_sol): # Max case, relax constraint a little to avoid infeasibility E_max = unique_equalityset(C, D, b, np.array([1.]), x_max - abs_tol / 3, abs_tol=abs_tol) else: E_max = np.nonzero(np.abs(np.dot(G, max_sol) - b) < abs_tol)[0] G = np.array([[1.], [-1.]]) g = np.array([x_max, -x_min]) # Relocate if trans: g = g + np.dot(G, xc0) # Return zero cols/rows E_max = nonzerorows[E_max] E_min = nonzerorows[E_min] if verbose > 0: print("Returning projection from dim " + str(d + k) + " to dim 1 \n") return G, g, [E_max, E_min] E = [] L = [] E_0, af, bf = shoot(C, D, b, abs_tol=abs_tol) ridge_list = ridge(C, D, b, E_0, af, bf, abs_tol=abs_tol, verbose=verbose) for i in range(len(ridge_list)): r = ridge_list[i] L.append(Ridge_Facet(r.E_r, r.ar, r.br, E_0, af, bf)) G = af.T g = bf if verbose > 0: print("\nStarting eq set " + str(E_0) + "\nStarting ridges ") for rr in L: print(str(rr.E_r)) E.append(E_0) while len(L) > 0: rid_fac1 = L[0] if verbose > 0: print("\nLooking for neighbors to " + str(rid_fac1.E_0) + " and " + str(rid_fac1.E_r) + " ..") E_adj, a_adj, b_adj = adjacent(C, D, b, rid_fac1, abs_tol=abs_tol) if verbose > 0: print("found neighbor " + str(E_adj) + ". \n\nLooking for ridges of neighbor..") ridge_list = ridge(C, D, b, E_adj, a_adj, b_adj, abs_tol=abs_tol, verbose=verbose) if verbose > 0: print("found " + str(len(ridge_list)) + " ridges\n") found_org = False for i in range(len(ridge_list)): r = ridge_list[i] E_r = r.E_r ar = r.ar br = r.br found = False for j in range(len(L)): rid_fac2 = L[j] A_r = rid_fac2.E_r if len(A_r) != len(E_r): continue t1 = np.sort(np.array(A_r)) t2 = np.sort(np.array(E_r)) if np.sum(np.abs(t1 - t2)) < abs_tol: found = True break if found: if verbose > 0: print("Ridge " + str(E_r) + " already visited, removing from L..") if rid_fac2 == rid_fac1: found_org = True L.remove(rid_fac2) else: if verbose > 0: print("Adding ridge-facet " + str(E_adj) + " " + str(E_r) + "") L.append(Ridge_Facet(E_r, ar, br, E_adj, a_adj, b_adj)) if not found_org: print("Expected ridge " + str(rid_fac1.E_r)) print("but got ridges ") for rid in ridge_list: print(rid.E_r) raise Exception( "esp: ridge did not return neighboring ridge as expected") G = np.vstack([G, a_adj]) g = np.hstack([g, b_adj]) E.append(E_adj) # Restore center if trans: g = g + np.dot(G, xc0) # Return zero rows for Ef in E: Ef = nonzerorows[Ef] return G, g, E