def test_primal_and_dual_infeasible_problem(self): self.n = 2 self.m = 4 self.P = sparse.csc_matrix((2, 2)) self.q = np.array([-1., -1.]) self.A = sparse.csc_matrix([[1., -1.], [-1., 1.], [1., 0.], [0., 1.]]) self.l = np.array([1., 1., 0., 0.]) self.u = np.inf * np.ones(self.m) self.model = osqp.OSQP() self.model.setup(P=self.P, q=self.q, A=self.A, l=self.l, u=self.u, **self.opts) # Warm start to avoid infeasibility detection at first step x0 = 25. * np.ones(self.n) y0 = -2. * np.ones(self.m) self.model.warm_start(x=x0, y=y0) # Solve res = self.model.solve() # Assert close self.assertIn(res.info.status_val, [ constant('OSQP_PRIMAL_INFEASIBLE'), constant('OSQP_DUAL_INFEASIBLE') ])
def test_primal_and_dual_infeasible_problem(self): self.n = 2 self.m = 4 self.P = sparse.csc_matrix((2, 2)) self.q = np.array([-1., -1.]) self.A = sparse.csc_matrix([[1., -1.], [-1., 1.], [1., 0.], [0., 1.]]) self.l = np.array([1., 1., 0., 0.]) self.u = np.inf * np.ones(self.m) self.model = osqp.OSQP() self.model.setup(P=self.P, q=self.q, A=self.A, l=self.l, u=self.u, **self.opts) res = self.model.solve() # Assert close self.assertIn(res.info.status_val, [ constant('OSQP_PRIMAL_INFEASIBLE'), constant('OSQP_DUAL_INFEASIBLE') ])
def linsys_solver_str_to_int(settings): linsys_solver_str = settings.pop('linsys_solver', '') if not isinstance(linsys_solver_str, str): raise TypeError("Setting linsys_solver " + "is required to be a string.") linsys_solver_str = linsys_solver_str.lower() if linsys_solver_str == 'cuda pcg': settings['linsys_solver'] = _osqp.constant('CUDA_PCG_SOLVER') # Default solver: CUDA PCG elif linsys_solver_str == '': settings['linsys_solver'] = _osqp.constant('CUDA_PCG_SOLVER') else: # default solver: CUDA PCG warn("Linear system solver not recognized. " + "Using default solver CUDA PCG.") settings['linsys_solver'] = _osqp.constant('CUDA_PCG_SOLVER') return settings
def test_primal_infeasible_problem(self): # Set random seed for reproducibility rg = Generator(PCG64(1)) self.n = 50 self.m = 500 # Generate random Matrices Pt = sparse.random(self.n, self.n, random_state=rg) self.P = sparse.triu(Pt.T.dot(Pt), format='csc') self.q = rg.standard_normal(self.n) self.A = sparse.random(self.m, self.n, random_state=rg).tolil() # Lil for efficiency self.u = 3 + rg.standard_normal(self.m) self.l = -3 + rg.standard_normal(self.m) # Make random problem primal infeasible self.A[int(self.n/2), :] = self.A[int(self.n/2)+1, :] self.l[int(self.n/2)] = self.u[int(self.n/2)+1] + 10 * rg.random() self.u[int(self.n/2)] = self.l[int(self.n/2)] + 0.5 # Convert A to csc self.A = self.A.tocsc() self.model = osqp.OSQP() self.model.setup(self.P, self.q, self.A, self.l, self.u, **self.opts) # Solve problem with OSQP res = self.model.solve() # Assert close self.assertEqual(res.info.status_val, constant('OSQP_PRIMAL_INFEASIBLE'))
def test_non_convex(self): # Setup workspace with new sigma opts = {'verbose': False, 'sigma': 5} self.model.setup(P=self.P, q=self.q, A=self.A, l=self.l, u=self.u, **opts) # Solve problem res = self.model.solve() # Assert close self.assertEqual(res.info.status_val, constant('OSQP_NON_CVX')) nptest.assert_approx_equal(res.info.obj_val, np.nan)
def test_dual_infeasible_qp(self): # Dual infeasible example self.P = sparse.diags([4., 0.], format='csc') self.q = np.array([0, 2]) self.A = sparse.csc_matrix([[1., 1.], [-1., 1.]]) self.l = np.array([-np.inf, -np.inf]) self.u = np.array([2., 3.]) self.model = osqp.OSQP() self.model.setup(P=self.P, q=self.q, A=self.A, l=self.l, u=self.u, **self.opts) # Solve problem with OSQP res = self.model.solve() # Assert close self.assertEqual(res.info.status_val, constant('OSQP_DUAL_INFEASIBLE'))
def test_dual_infeasible_lp(self): # Dual infeasible example self.P = sparse.csc_matrix((2, 2)) self.q = np.array([2, -1]) self.A = sparse.eye(2, format='csc') self.l = np.array([0., 0.]) self.u = np.array([np.inf, np.inf]) self.model = osqp.OSQP() self.model.setup(P=self.P, q=self.q, A=self.A, l=self.l, u=self.u, **self.opts) # Solve problem with OSQP res = self.model.solve() # Assert close self.assertEqual(res.info.status_val, constant('OSQP_DUAL_INFEASIBLE'))
def test_primal_infeasible_problem(self): # Simple QP problem sp.random.seed(4) self.n = 50 self.m = 500 # Generate random Matrices Pt = sparse.random(self.n, self.n) self.P = sparse.triu(Pt.T.dot(Pt), format='csc') self.q = sp.randn(self.n) self.A = sparse.random(self.m, self.n).tolil() # Lil for efficiency self.u = 3 + sp.randn(self.m) self.l = -3 + sp.randn(self.m) # Make random problem primal infeasible self.A[int(self.n / 2), :] = self.A[int(self.n / 2) + 1, :] self.l[int(self.n / 2)] = self.u[int(self.n / 2) + 1] + 10 * sp.rand() self.u[int(self.n / 2)] = self.l[int(self.n / 2)] + 0.5 # Convert A to csc self.A = self.A.tocsc() self.model = osqp.OSQP() self.model.setup(P=self.P, q=self.q, A=self.A, l=self.l, u=self.u, **self.opts) # Solve problem with OSQP res = self.model.solve() # Assert close self.assertEqual(res.info.status_val, constant('OSQP_PRIMAL_INFEASIBLE'))
def prepare_data(P=None, q=None, A=None, l=None, u=None, **settings): """ Prepare problem data of the form minimize 1/2 x' * P * x + q' * x subject to l <= A * x <= u solver settings can be specified as additional keyword arguments """ # # Get problem dimensions # if P is None: if q is not None: n = len(q) elif A is not None: n = A.shape[1] else: raise ValueError("The problem does not have any variables") else: n = P.shape[0] if A is None: m = 0 else: m = A.shape[0] # # Create parameters if they are None # if (A is None and (l is not None or u is not None)) or \ (A is not None and (l is None and u is None)): raise ValueError("A must be supplied together " + "with at least one bound l or u") # Add infinity bounds in case they are not specified if A is not None and l is None: l = -np.inf * np.ones(A.shape[0]) if A is not None and u is None: u = np.inf * np.ones(A.shape[0]) # Create elements if they are not specified if P is None: P = sparse.csc_matrix((np.zeros((0,), dtype=np.double), np.zeros((0,), dtype=np.int), np.zeros((n+1,), dtype=np.int)), shape=(n, n)) if q is None: q = np.zeros(n) if A is None: A = sparse.csc_matrix((np.zeros((0,), dtype=np.double), np.zeros((0,), dtype=np.int), np.zeros((n+1,), dtype=np.int)), shape=(m, n)) l = np.zeros(A.shape[0]) u = np.zeros(A.shape[0]) # # Check vector dimensions (not checked from C solver) # # Check if second dimension of A is correct # if A.shape[1] != n: # raise ValueError("Dimension n in A and P does not match") if len(q) != n: raise ValueError("Incorrect dimension of q") if len(l) != m: raise ValueError("Incorrect dimension of l") if len(u) != m: raise ValueError("Incorrect dimension of u") # # Check or Sparsify Matrices # if not sparse.issparse(P) and isinstance(P, np.ndarray) and \ len(P.shape) == 2: raise TypeError("P is required to be a sparse matrix") if not sparse.issparse(A) and isinstance(A, np.ndarray) and \ len(A.shape) == 2: raise TypeError("A is required to be a sparse matrix") # If P is not triu, then convert it to triu if sparse.tril(P, -1).data.size > 0: P = sparse.triu(P, format='csc') # Convert matrices in CSC form and to individual pointers if not sparse.isspmatrix_csc(P): warn("Converting sparse P to a CSC " + "(compressed sparse column) matrix. (It may take a while...)") P = P.tocsc() if not sparse.isspmatrix_csc(A): warn("Converting sparse A to a CSC " + "(compressed sparse column) matrix. (It may take a while...)") A = A.tocsc() # Check if P an A have sorted indices if not P.has_sorted_indices: P.sort_indices() if not A.has_sorted_indices: A.sort_indices() # Convert infinity values to OSQP Infinity u = np.minimum(u, _osqp.constant('OSQP_INFTY')) l = np.maximum(l, -_osqp.constant('OSQP_INFTY')) # Convert linsys_solver string to integer settings = linsys_solver_str_to_int(settings) return ((n, m), P.data, P.indices, P.indptr, q, A.data, A.indices, A.indptr, l, u), settings
def update(self, q=None, l=None, u=None, Px=None, Px_idx=np.array([]), Ax=None, Ax_idx=np.array([])): """ Update OSQP problem arguments """ # get problem dimensions (n, m) = self._model.dimensions() # check consistency of the input arguments if q is not None and len(q) != n: raise ValueError("q must have length n") if l is not None: if not isinstance(l, np.ndarray): raise TypeError("l must be numpy.ndarray, not %s" % type(l).__name__) elif len(l) != m: raise ValueError("l must have length m") # Convert values to -OSQP_INFTY l = np.maximum(l, -_osqp.constant('OSQP_INFTY')) if u is not None: if not isinstance(u, np.ndarray): raise TypeError("u must be numpy.ndarray, not %s" % type(u).__name__) elif len(u) != m: raise ValueError("u must have length m") # Convert values to OSQP_INFTY u = np.minimum(u, _osqp.constant('OSQP_INFTY')) if Ax is None: if len(Ax_idx) > 0: raise ValueError("Vector Ax has not been specified") else: if len(Ax_idx) > 0 and len(Ax) != len(Ax_idx): raise ValueError("Ax and Ax_idx must have the same lengths") if Px is None: if len(Px_idx) > 0: raise ValueError("Vector Px has not been specified") else: if len(Px_idx) > 0 and len(Px) != len(Px_idx): raise ValueError("Px and Px_idx must have the same lengths") if q is None and l is None and u is None and Px is None and Ax is None: raise ValueError("No updatable data has been specified") # update linear cost if q is not None: self._model.update_lin_cost(q) # update lower bound if l is not None and u is None: self._model.update_bounds(l, np.array([])) # update upper bound if u is not None and l is None: self._model.update_bounds(np.array([]), u) # update bounds if l is not None and u is not None: self._model.update_bounds(l, u) # update matrix P if Px is not None and Ax is None: self._model.update_P(Px, Px_idx, len(Px)) # update matrix A if Ax is not None and Px is None: self._model.update_A(Ax, Ax_idx, len(Ax)) # update matrices P and A if Px is not None and Ax is not None: self._model.update_P_A(Px, Px_idx, len(Px), Ax, Ax_idx, len(Ax))