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 test_update_time_limit(self): res = self.model.solve() self.assertEqual(res.info.status_val, constant('OSQP_SOLVED')) # Ensure the solver will time out self.model.update_settings(time_limit=1e-6, verbose=True, max_iter=2000000000, eps_abs=1e-20, eps_rel=1e-20, check_termination=0) res = self.model.solve() self.assertEqual(res.info.status_val, constant('OSQP_TIME_LIMIT_REACHED'))
def test_update_max_iter(self): self.model.update_settings(max_iter=80) res = self.model.solve() # Assert max iter reached self.assertEqual(res.info.status_val, constant('OSQP_MAX_ITER_REACHED'))
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 == 'qdldl': settings['linsys_solver'] = _osqp.constant('QDLDL_SOLVER') elif linsys_solver_str == 'mkl pardiso': settings['linsys_solver'] = _osqp.constant('MKL_PARDISO_SOLVER') # Default solver: QDLDL elif linsys_solver_str == '': settings['linsys_solver'] = _osqp.constant('QDLDL_SOLVER') else: # default solver: QDLDL warn("Linear system solver not recognized. " + "Using default solver QDLDL.") settings['linsys_solver'] = _osqp.constant('QDLDL_SOLVER') return settings
def test_non_convex_big_sigma(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 = np.random.rand(self.n, self.n) self.P = sparse.triu(Pt.T.dot(Pt), format='csc') self.q = np.random.rand(self.n) self.A = sparse.random(self.m, self.n).tolil() # Lil for efficiency self.u = 3 + np.random.randn(self.m) self.l = -3 + np.random.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 * np.random.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 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_lower_bound(l) # update upper bound if u is not None and l is None: self._model.update_upper_bound(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))
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 test_nan(self): nptest.assert_approx_equal(constant('OSQP_NAN'), np.nan)