def test_div_expression(self): # Vectors exp = self.x/2 self.assertEqual(exp.curvature, u.Curvature.AFFINE_KEY) self.assertEqual(exp.sign, u.Sign.UNKNOWN_KEY) self.assertEqual(exp.canonical_form[0].size, (2,1)) self.assertEqual(exp.canonical_form[1], []) # self.assertEqual(exp.name(), c.name() + " * " + self.x.name()) self.assertEqual(exp.size, (2,1)) with self.assertRaises(Exception) as cm: (self.x/[2,2,3]) print cm.exception self.assertEqual(str(cm.exception), "Can only divide by a scalar constant.") # Constant expressions. c = Constant(2) exp = c/(3 - 5) self.assertEqual(exp.curvature, u.Curvature.CONSTANT_KEY) self.assertEqual(exp.size, (1,1)) self.assertEqual(exp.sign, u.Sign.NEGATIVE_KEY) # Parameters. p = Parameter(sign="positive") exp = 2/p p.value = 2 self.assertEquals(exp.value, 1)
def test_parameters(self): p = Parameter(name='p') self.assertEqual(p.name(), "p") self.assertEqual(p.size, (1,1)) p = Parameter(4, 3, sign="positive") with self.assertRaises(Exception) as cm: p.value = 1 self.assertEqual(str(cm.exception), "Invalid dimensions (1,1) for Parameter value.") val = -np.ones((4,3)) val[0,0] = 2 p = Parameter(4, 3, sign="positive") with self.assertRaises(Exception) as cm: p.value = val self.assertEqual(str(cm.exception), "Invalid sign for Parameter value.") p = Parameter(4, 3, sign="negative") with self.assertRaises(Exception) as cm: p.value = val self.assertEqual(str(cm.exception), "Invalid sign for Parameter value.") # No error for unknown sign. p = Parameter(4, 3) p.value = val
def test_huber(self): # Valid. huber(self.x, 1) with self.assertRaises(Exception) as cm: huber(self.x, -1) self.assertEqual(str(cm.exception), "M must be a non-negative scalar constant.") with self.assertRaises(Exception) as cm: huber(self.x, [1,1]) self.assertEqual(str(cm.exception), "M must be a non-negative scalar constant.") # M parameter. M = Parameter(sign="positive") # Valid. huber(self.x, M) M.value = 1 self.assertAlmostEquals(huber(2, M).value, 3) # Invalid. M = Parameter(sign="negative") with self.assertRaises(Exception) as cm: huber(self.x, M) self.assertEqual(str(cm.exception), "M must be a non-negative scalar constant.")
def test_parameter_expressions(self): """Test that expressions with parameters are updated properly. """ x = Variable() y = Variable() x0 = Parameter() xSquared = x0*x0 + 2*x0*(x - x0) # initial guess for x x0.value = 2 # make the constraint x**2 - y == 0 g = xSquared - y # set up the problem obj = abs(x - 1) prob = Problem( Minimize( obj ), [ g == 0 ] ) prob.solve() x0.value = 1 prob.solve() self.assertAlmostEqual(g.value, 0) # Test multiplication. prob = Problem( Minimize( x0*x ), [ x == 1 ] ) x0.value = 2 prob.solve() x0.value = 1 prob.solve() self.assertAlmostEqual(prob.value, 1)
def test_1D_array(self): """Test NumPy 1D arrays as constants. """ c = np.array([1, 2]) p = Parameter(2) p.value = [1, 1] self.assertEqual((c @ p).value, 3) self.assertEqual((c @ self.x).shape, tuple())
def test_param_copy(self): """Test the copy function for Parameters. """ x = Parameter((3, 4), name="x", nonneg=True) y = x.copy() self.assertEqual(y.shape, (3, 4)) self.assertEqual(y.name(), "x") self.assertEqual(y.sign, "NONNEGATIVE")
def test_1D_array(self): """Test NumPy 1D arrays as constants. """ c = np.array([1, 2]) p = Parameter(2) p.value = [1, 1] self.assertEqual((c*p).value, 3) self.assertEqual((c*self.x).size, (1, 1))
def test_param_copy(self): """Test the copy function for Parameters. """ x = Parameter(3, 4, name="x", sign="positive") y = x.copy() self.assertEqual(y.size, (3, 4)) self.assertEqual(y.name(), "x") self.assertEqual(y.sign, "POSITIVE")
def test_parameters(self): """Test the parameters method. """ p1 = Parameter() p2 = Parameter(3, sign="negative") p3 = Parameter(4, 4, sign="positive") p = Problem(Minimize(p1), [self.a + p1 <= p2, self.b <= p3 + p3 + 2]) params = p.parameters() self.assertItemsEqual(params, [p1, p2, p3])
def test_presolve_parameters(self): """Test presolve with parameters. """ # Test with parameters. gamma = Parameter(sign="positive") x = Variable() obj = Minimize(x) prob = Problem(obj, [gamma == 1, x >= 0]) gamma.value = 0 prob.solve(solver=s.SCS) self.assertEqual(prob.status, s.INFEASIBLE) gamma.value = 1 prob.solve(solver=s.CVXOPT) self.assertEqual(prob.status, s.OPTIMAL)
def test_kron(self): """Test the kron atom. """ a = np.ones((3,2)) b = Parameter(2, sign='positive') expr = kron(a, b) assert expr.is_positive() self.assertEqual(expr.size, (6, 2)) b = Parameter(2, sign='negative') expr = kron(a, b) assert expr.is_negative() with self.assertRaises(Exception) as cm: kron(self.x, -1) self.assertEqual(str(cm.exception), "The first argument to kron must be constant.")
def test_kron(self): """Test the kron atom. """ a = np.ones((3, 2)) b = Parameter((2, 1), nonneg=True) expr = cp.kron(a, b) assert expr.is_nonneg() self.assertEqual(expr.shape, (6, 2)) b = Parameter((2, 1), nonpos=True) expr = cp.kron(a, b) assert expr.is_nonpos() with self.assertRaises(Exception) as cm: cp.kron(self.x, -1) self.assertEqual(str(cm.exception), "The first argument to kron must be constant.")
def test_parameter_problems(self): """Test problems with parameters. """ p1 = Parameter() p2 = Parameter(3, sign="negative") p3 = Parameter(4, 4, sign="positive") p = Problem(Maximize(p1*self.a), [self.a + p1 <= p2, self.b <= p3 + p3 + 2]) p1.value = 2 p2.value = -numpy.ones((3,1)) p3.value = numpy.ones((4, 4)) result = p.solve() self.assertAlmostEqual(result, -6)
def test_quad_form(self): """Test quad_form atom. """ P = Parameter(2,2) with self.assertRaises(Exception) as cm: quad_form(self.x, P) self.assertEqual(str(cm.exception), "P cannot be a parameter.")
def test_atom(): for atom_list, objective_type in atoms: for atom, size, args, obj_val in atom_list: for row in range(size[0]): for col in range(size[1]): for solver in SOLVERS_TO_TRY: # Atoms with Constant arguments. const_args = [Constant(arg) for arg in args] yield (run_atom, atom, Problem( objective_type(atom(*const_args)[row, col])), obj_val[row, col].value, solver) # Atoms with Variable arguments. variables = [] constraints = [] for idx, expr in enumerate(args): variables.append(Variable(*intf.size(expr))) constraints.append(variables[-1] == expr) objective = objective_type(atom(*variables)[row, col]) yield (run_atom, atom, Problem(objective, constraints), obj_val[row, col].value, solver) # Atoms with Parameter arguments. parameters = [] for expr in args: parameters.append(Parameter(*intf.size(expr))) parameters[ -1].value = intf.DEFAULT_INTF.const_to_matrix( expr) objective = objective_type(atom(*parameters)[row, col]) yield (run_atom, atom, Problem(objective), obj_val[row, col].value, solver)
def test_constant_atoms(atom_info, objective_type) -> None: atom, size, args, obj_val = atom_info for indexer in get_indices(size): for solver in SOLVERS_TO_TRY: # Atoms with Constant arguments. prob_val = obj_val[indexer].value const_args = [Constant(arg) for arg in args] problem = Problem(objective_type(atom(*const_args)[indexer])) run_atom(atom, problem, prob_val, solver) # Atoms with Variable arguments. variables = [] constraints = [] for idx, expr in enumerate(args): variables.append(Variable(intf.shape(expr))) constraints.append(variables[-1] == expr) objective = objective_type(atom(*variables)[indexer]) new_obj_val = prob_val if objective_type == cp.Maximize: objective = -objective new_obj_val = -new_obj_val problem = Problem(objective, constraints) run_atom(atom, problem, new_obj_val, solver) # Atoms with Parameter arguments. parameters = [] for expr in args: parameters.append(Parameter(intf.shape(expr))) parameters[-1].value = intf.DEFAULT_INTF.const_to_matrix(expr) objective = objective_type(atom(*parameters)[indexer]) run_atom(atom, Problem(objective), prob_val, solver)
def test_atom(): for atom_list, objective_type in atoms: for atom, obj_val in atom_list: for row in xrange(atom.size[0]): for col in xrange(atom.size[1]): # Atoms with Constant arguments. yield run_atom, Problem(objective_type( atom[row, col])), obj_val[row, col].value # Atoms with Variable arguments. variables = [] constraints = [] for expr in atom.subexpressions: variables.append(Variable(*expr.size)) constraints.append(variables[-1] == expr) atom_func = atom.__class__ objective = objective_type(atom_func(*variables)[row, col]) yield run_atom, Problem(objective, constraints), obj_val[row, col].value # Atoms with Parameter arguments. parameters = [] for expr in atom.subexpressions: parameters.append(Parameter(*expr.size)) parameters[-1].value = expr.value objective = objective_type( atom_func(*parameters)[row, col]) yield run_atom, Problem(objective), obj_val[row, col].value
def test_partial_optimize_params(self): """Test partial optimize with parameters. """ x, y = Variable(1), Variable(1) gamma = Parameter() # Solve the (simple) two-stage problem by "combining" the two stages (i.e., by solving a single linear program) p1 = Problem(Minimize(x+y), [x+y>=gamma, y>=4, x>=5]) gamma.value = 3 p1.solve() # Solve the two-stage problem via partial_optimize p2 = Problem(Minimize(y), [x+y>=gamma, y>=4]) g = partial_optimize(p2, [y], [x]) p3 = Problem(Minimize(x+g), [x>=5]) p3.solve() self.assertAlmostEqual(p1.value, p3.value)
def test_atom(): for atom_list, objective_type in atoms: for atom, obj_val in atom_list: for row in xrange(atom.size[0]): for col in xrange(atom.size[1]): for solver in [ECOS, SCS, CVXOPT]: # Atoms with Constant arguments. yield (run_atom, atom, Problem(objective_type(atom[row, col])), obj_val[row, col].value, solver) # Atoms with Variable arguments. variables = [] constraints = [] for idx, expr in enumerate(atom.subexpressions): # Special case for MulExpr because # can't multiply two variables. if (idx == 0 and isinstance(atom, MulExpression)): variables.append(expr) else: variables.append(Variable(*expr.size)) constraints.append(variables[-1] == expr) atom_func = atom.__class__ objective = objective_type( atom_func(*variables)[row, col]) yield (run_atom, atom, Problem(objective, constraints), obj_val[row, col].value, solver) # Atoms with Parameter arguments. parameters = [] for expr in atom.subexpressions: parameters.append(Parameter(*expr.size)) parameters[-1].value = expr.value objective = objective_type( atom_func(*parameters)[row, col]) yield (run_atom, atom, Problem(objective), obj_val[row, col].value, solver)
def prox_step(prob, rho_init, scaled=False, spectral=False): """Formulates the proximal operator for a given objective, constraints, and step size. Parikh, Boyd. "Proximal Algorithms." Parameters ---------- prob : Problem The objective and constraints associated with the proximal operator. The sign of the objective function is flipped if `prob` is a maximization problem. rho_init : float The initial step size. scaled : logical, optional Should the dual variable be scaled? spectral : logical, optional Will spectral step sizes be used? Returns ---------- prox : Problem The proximal step problem. vmap : dict A map of each proximal variable id to a dictionary containing that variable `x`, the mean variable parameter `xbar`, the associated dual parameter `y`, and the step size parameter `rho`. If `spectral = True`, the estimated dual parameter `yhat` is also included. """ vmap = {} # Store consensus variables f = flip_obj(prob).args[0] # Add penalty for each variable. for xvar in prob.variables(): xid = xvar.id shape = xvar.shape vmap[xid] = { "x": xvar, "xbar": Parameter(shape, value=np.zeros(shape)), "y": Parameter(shape, value=np.zeros(shape)), "rho": Parameter(value=rho_init[xid], nonneg=True) } if spectral: vmap[xid]["yhat"] = Parameter(shape, value=np.zeros(shape)) dual = vmap[xid]["y"] if scaled else vmap[xid]["y"] / vmap[xid]["rho"] f += (vmap[xid]["rho"] / 2.0) * sum_squares(xvar - vmap[xid]["xbar"] + dual) prox = Problem(Minimize(f), prob.constraints) return prox, vmap
def test_param(self): """Test creating a parameter. """ A = Parameter(5, 4) var = create_param(A, (5, 4)) self.assertEqual(var.size, (5, 4)) self.assertEqual(len(var.args), 0) self.assertEqual(var.type, PARAM)
def test_1D_array(self): """Test NumPy 1D arrays as constants. """ c = np.array([1,2]) p = Parameter(2) with warnings.catch_warnings(record=True) as w: # Cause all warnings to always be triggered. warnings.simplefilter("always") # Trigger a warning. Constant(c) self.x + c p.value = c # Verify some things self.assertEqual(len(w), 3) for warning in w: self.assertEqual(str(warning.message), "NumPy 1D arrays are treated as column vectors.")
def test_conv(self): """Test the conv atom. """ a = np.ones((3,1)) b = Parameter(2, sign='positive') expr = conv(a, b) assert expr.is_positive() self.assertEqual(expr.size, (4, 1)) b = Parameter(2, sign='negative') expr = conv(a, b) assert expr.is_negative() with self.assertRaises(Exception) as cm: conv(self.x, -1) self.assertEqual(str(cm.exception), "The first argument to conv must be constant.") with self.assertRaises(Exception) as cm: conv([[0,1],[0,1]], self.x) self.assertEqual(str(cm.exception), "The arguments to conv must resolve to vectors." )
def test_conv(self): """Test the conv atom. """ a = np.ones((3, 1)) b = Parameter(2, nonneg=True) expr = cp.conv(a, b) assert expr.is_nonneg() self.assertEqual(expr.shape, (4, 1)) b = Parameter(2, nonpos=True) expr = cp.conv(a, b) assert expr.is_nonpos() with self.assertRaises(Exception) as cm: cp.conv(self.x, -1) self.assertEqual(str(cm.exception), "The first argument to conv must be constant.") with self.assertRaises(Exception) as cm: cp.conv([[0, 1], [0, 1]], self.x) self.assertEqual(str(cm.exception), "The arguments to conv must resolve to vectors.")
def test_huber(self): # Valid. huber(self.x, 1) with self.assertRaises(Exception) as cm: huber(self.x, -1) self.assertEqual(str(cm.exception), "M must be a non-negative scalar constant.") with self.assertRaises(Exception) as cm: huber(self.x, [1,1]) self.assertEqual(str(cm.exception), "M must be a non-negative scalar constant.") # M parameter. M = Parameter(sign="positive") # Valid. huber(self.x, M) M.value = 1 self.assertAlmostEquals(huber(2, M).value, 3) # Invalid. M = Parameter(sign="negative") with self.assertRaises(Exception) as cm: huber(self.x, M) self.assertEqual(str(cm.exception), "M must be a non-negative scalar constant.") # Test copy with args=None atom = huber(self.x, 2) copy = atom.copy() self.assertTrue(type(copy) is type(atom)) # A new object is constructed, so copy.args == atom.args but copy.args # is not atom.args. self.assertEqual(copy.args, atom.args) self.assertFalse(copy.args is atom.args) # As get_data() returns a Constant, we have to check the value self.assertEqual(copy.get_data().value, atom.get_data().value) # Test copy with new args copy = atom.copy(args=[self.y]) self.assertTrue(type(copy) is type(atom)) self.assertTrue(copy.args[0] is self.y) self.assertEqual(copy.get_data().value, atom.get_data().value)
def test_huber(self): # Valid. cp.huber(self.x, 1) with self.assertRaises(Exception) as cm: cp.huber(self.x, -1) self.assertEqual(str(cm.exception), "M must be a non-negative scalar constant.") with self.assertRaises(Exception) as cm: cp.huber(self.x, [1, 1]) self.assertEqual(str(cm.exception), "M must be a non-negative scalar constant.") # M parameter. M = Parameter(nonneg=True) # Valid. cp.huber(self.x, M) M.value = 1 self.assertAlmostEqual(cp.huber(2, M).value, 3) # Invalid. M = Parameter(nonpos=True) with self.assertRaises(Exception) as cm: cp.huber(self.x, M) self.assertEqual(str(cm.exception), "M must be a non-negative scalar constant.") # Test copy with args=None atom = cp.huber(self.x, 2) copy = atom.copy() self.assertTrue(type(copy) is type(atom)) # A new object is constructed, so copy.args == atom.args but copy.args # is not atom.args. self.assertEqual(copy.args, atom.args) self.assertFalse(copy.args is atom.args) # As get_data() returns a Constant, we have to check the value self.assertEqual(copy.get_data()[0].value, atom.get_data()[0].value) # Test copy with new args copy = atom.copy(args=[self.y]) self.assertTrue(type(copy) is type(atom)) self.assertTrue(copy.args[0] is self.y) self.assertEqual(copy.get_data()[0].value, atom.get_data()[0].value)
def test_multiply(self): """Test the multiply atom. """ self.assertEqual(cp.multiply([1, -1], self.x).sign, s.UNKNOWN) self.assertEqual(cp.multiply([1, -1], self.x).curvature, s.AFFINE) self.assertEqual(cp.multiply([1, -1], self.x).shape, (2,)) pos_param = Parameter(2, nonneg=True) neg_param = Parameter(2, nonpos=True) self.assertEqual(cp.multiply(pos_param, pos_param).sign, s.NONNEG) self.assertEqual(cp.multiply(pos_param, neg_param).sign, s.NONPOS) self.assertEqual(cp.multiply(neg_param, neg_param).sign, s.NONNEG) self.assertEqual(cp.multiply(neg_param, cp.square(self.x)).curvature, s.CONCAVE) # Test promotion. self.assertEqual(cp.multiply([1, -1], 1).shape, (2,)) self.assertEqual(cp.multiply(1, self.C).shape, self.C.shape) self.assertEqual(cp.multiply(self.x, [1, -1]).sign, s.UNKNOWN) self.assertEqual(cp.multiply(self.x, [1, -1]).curvature, s.AFFINE) self.assertEqual(cp.multiply(self.x, [1, -1]).shape, (2,))
def test_parameter_expressions(self): """Test that expressions with parameters are updated properly. """ x = Variable() y = Variable() x0 = Parameter() xSquared = x0 * x0 + 2 * x0 * (x - x0) # initial guess for x x0.value = 2 # make the constraint x**2 - y == 0 g = xSquared - y # set up the problem obj = abs(x - 1) prob = Problem(Minimize(obj), [g == 0]) prob.solve() x0.value = 1 prob.solve() self.assertAlmostEqual(g.value, 0) # Test multiplication. prob = Problem(Minimize(x0 * x), [x == 1]) x0.value = 2 prob.solve() x0.value = 1 prob.solve() self.assertAlmostEqual(prob.value, 1)
def test_mul_elemwise(self): """Test the mul_elemwise atom. """ self.assertEquals(mul_elemwise([1, -1], self.x).sign, u.Sign.UNKNOWN_KEY) self.assertEquals(mul_elemwise([1, -1], self.x).curvature, u.Curvature.AFFINE_KEY) self.assertEquals(mul_elemwise([1, -1], self.x).size, (2, 1)) pos_param = Parameter(2, sign="positive") neg_param = Parameter(2, sign="negative") self.assertEquals(mul_elemwise(pos_param, pos_param).sign, u.Sign.POSITIVE_KEY) self.assertEquals(mul_elemwise(pos_param, neg_param).sign, u.Sign.NEGATIVE_KEY) self.assertEquals(mul_elemwise(neg_param, neg_param).sign, u.Sign.POSITIVE_KEY) self.assertEquals(mul_elemwise(neg_param, square(self.x)).curvature, u.Curvature.CONCAVE_KEY) # Test promotion. self.assertEquals(mul_elemwise([1, -1], 1).size, (2, 1)) self.assertEquals(mul_elemwise(1, self.C).size, self.C.size) with self.assertRaises(Exception) as cm: mul_elemwise(self.x, [1, -1]) self.assertEqual(str(cm.exception), "The first argument to mul_elemwise must be constant.")
def test_div_expression(self): # Vectors exp = self.x/2 self.assertEqual(exp.curvature, s.AFFINE) self.assertEqual(exp.sign, s.UNKNOWN) self.assertEqual(exp.canonical_form[0].size, (2, 1)) self.assertEqual(exp.canonical_form[1], []) # self.assertEqual(exp.name(), c.name() + " * " + self.x.name()) self.assertEqual(exp.size, (2, 1)) with self.assertRaises(Exception) as cm: (self.x/[2, 2, 3]) print(cm.exception) self.assertEqual(str(cm.exception), "Can only divide by a scalar constant.") # Constant expressions. c = Constant(2) exp = c/(3 - 5) self.assertEqual(exp.curvature, s.CONSTANT) self.assertEqual(exp.size, (1, 1)) self.assertEqual(exp.sign, s.NEGATIVE) # Parameters. p = Parameter(sign="positive") exp = 2/p p.value = 2 self.assertEqual(exp.value, 1) rho = Parameter(sign="positive") rho.value = 1 self.assertEqual(rho.sign, s.POSITIVE) self.assertEqual(Constant(2).sign, s.POSITIVE) self.assertEqual((Constant(2)/Constant(2)).sign, s.POSITIVE) self.assertEqual((Constant(2)*rho).sign, s.POSITIVE) self.assertEqual((rho/2).sign, s.POSITIVE)
def test_div_expression(self): # Vectors exp = self.x/2 self.assertEqual(exp.curvature, s.AFFINE) self.assertEqual(exp.sign, s.UNKNOWN) # self.assertEqual(exp.canonical_form[0].shape, (2, 1)) # self.assertEqual(exp.canonical_form[1], []) # self.assertEqual(exp.name(), c.name() + " * " + self.x.name()) self.assertEqual(exp.shape, (2,)) with self.assertRaises(Exception) as cm: (self.x/[2, 2, 3]) print(cm.exception) self.assertRegexpMatches(str(cm.exception), "Incompatible shapes for division.*") c = Constant([3.0, 4.0, 12.0]) self.assertItemsAlmostEqual( (c / Constant([1.0, 2.0, 3.0])).value, np.array([3.0, 2.0, 4.0])) # Constant expressions. c = Constant(2) exp = c/(3 - 5) self.assertEqual(exp.curvature, s.CONSTANT) self.assertEqual(exp.shape, tuple()) self.assertEqual(exp.sign, s.NONPOS) # Parameters. p = Parameter(nonneg=True) exp = 2/p p.value = 2 self.assertEqual(exp.value, 1) rho = Parameter(nonneg=True) rho.value = 1 self.assertEqual(rho.sign, s.NONNEG) self.assertEqual(Constant(2).sign, s.NONNEG) self.assertEqual((Constant(2)/Constant(2)).sign, s.NONNEG) self.assertEqual((Constant(2)*rho).sign, s.NONNEG) self.assertEqual((rho/2).sign, s.NONNEG) # Broadcasting. x = cp.Variable((3, 3)) c = np.arange(1, 4)[:, None] expr = x / c self.assertEqual((3, 3), expr.shape) x.value = np.ones((3, 3)) A = np.ones((3, 3)) / c self.assertItemsAlmostEqual(A, expr.value) with self.assertRaises(Exception) as cm: (x/c[:, 0]) print(cm.exception) self.assertRegexpMatches(str(cm.exception), "Incompatible shapes for division.*")
def test_div_expression(self): # Vectors exp = self.x / 2 self.assertEqual(exp.curvature, u.Curvature.AFFINE_KEY) self.assertEqual(exp.sign, u.Sign.UNKNOWN_KEY) self.assertEqual(exp.canonical_form[0].size, (2, 1)) self.assertEqual(exp.canonical_form[1], []) # self.assertEqual(exp.name(), c.name() + " * " + self.x.name()) self.assertEqual(exp.size, (2, 1)) with self.assertRaises(Exception) as cm: (self.x / [2, 2, 3]) print(cm.exception) self.assertEqual(str(cm.exception), "Can only divide by a scalar constant.") # Constant expressions. c = Constant(2) exp = c / (3 - 5) self.assertEqual(exp.curvature, u.Curvature.CONSTANT_KEY) self.assertEqual(exp.size, (1, 1)) self.assertEqual(exp.sign, u.Sign.NEGATIVE_KEY) # Parameters. p = Parameter(sign="positive") exp = 2 / p p.value = 2 self.assertEquals(exp.value, 1) rho = Parameter(sign="positive") rho.value = 1 self.assertEquals(rho.sign, u.Sign.POSITIVE_KEY) self.assertEquals(Constant(2).sign, u.Sign.POSITIVE_KEY) self.assertEquals((Constant(2) / Constant(2)).sign, u.Sign.POSITIVE_KEY) self.assertEquals((Constant(2) * rho).sign, u.Sign.POSITIVE_KEY) self.assertEquals((rho / 2).sign, u.Sign.POSITIVE_KEY)
def test_div_expression(self): # Vectors exp = self.x / 2 self.assertEqual(exp.curvature, s.AFFINE) self.assertEqual(exp.sign, s.UNKNOWN) # self.assertEqual(exp.canonical_form[0].shape, (2, 1)) # self.assertEqual(exp.canonical_form[1], []) # self.assertEqual(exp.name(), c.name() + " * " + self.x.name()) self.assertEqual(exp.shape, (2, )) with self.assertRaises(Exception) as cm: (self.x / [2, 2, 3]) print(cm.exception) self.assertEqual(str(cm.exception), "Can only divide by a scalar constant.") # Constant expressions. c = Constant(2) exp = c / (3 - 5) self.assertEqual(exp.curvature, s.CONSTANT) self.assertEqual(exp.shape, tuple()) self.assertEqual(exp.sign, s.NONPOS) # Parameters. p = Parameter(nonneg=True) exp = 2 / p p.value = 2 self.assertEqual(exp.value, 1) rho = Parameter(nonneg=True) rho.value = 1 self.assertEqual(rho.sign, s.NONNEG) self.assertEqual(Constant(2).sign, s.NONNEG) self.assertEqual((Constant(2) / Constant(2)).sign, s.NONNEG) self.assertEqual((Constant(2) * rho).sign, s.NONNEG) self.assertEqual((rho / 2).sign, s.NONNEG)
def test_get_coefficients(self): """Test the get_coefficients function. """ size = (5, 4) # Eye x = create_var(size) coeffs = get_coefficients(x) assert len(coeffs) == 1 id_, mat = coeffs[0] self.assertEqual(id_, x.data) self.assertItemsAlmostEqual(mat.todense(), sp.eye(20).todense()) # Eye with scalar mult. x = create_var(size) A = create_const(5, (1, 1)) coeffs = get_coefficients(mul_expr(A, x, size)) assert len(coeffs) == 1 id_, mat = coeffs[0] self.assertItemsAlmostEqual(mat.todense(), 5*sp.eye(20).todense()) # Promoted x = create_var((1, 1)) coeffs = get_coefficients(promote(x, size)) assert len(coeffs) == 1 id_, mat = coeffs[0] self.assertEqual(mat.shape, (20, 1)) self.assertItemsAlmostEqual(mat, np.ones((20, 1))) # Normal size = (5, 5) x = create_var((5, 1)) A = create_const(np.ones(size), size) coeffs = get_coefficients(mul_expr(A, x, (5, 1))) assert len(coeffs) == 1 id_, mat = coeffs[0] self.assertEqual(mat.shape, (5, 5)) self.assertItemsAlmostEqual(mat.todense(), A.data) # Blocks size = (5, 5) x = create_var(size) A = create_const(np.ones(size), size) coeffs = get_coefficients(mul_expr(A, x, size)) assert len(coeffs) == 1 id_, mat = coeffs[0] self.assertEqual(mat.shape, (25, 25)) self.assertItemsAlmostEqual(mat.todense(), sp.block_diag(5*[np.ones(size)]).todense()) # Scalar constant size = (1, 1) A = create_const(5, size) coeffs = get_coefficients(A) assert len(coeffs) == 1 id_, mat = coeffs[0] self.assertEqual(intf.size(mat), (1, 1)) self.assertEqual(mat, 5) # Dense constant size = (5, 4) A = create_const(np.ones(size), size) coeffs = get_coefficients(A) assert len(coeffs) == 1 id_, mat = coeffs[0] self.assertEqual(mat.shape, (size[0]*size[1], 1)) self.assertItemsAlmostEqual(mat, np.ones(size)) # Sparse constant size = (5, 5) A = create_const(sp.eye(5), size) coeffs = get_coefficients(A) assert len(coeffs) == 1 id_, mat = coeffs[0] self.assertEqual(mat.shape, (size[0]*size[1], 1)) self.assertItemsAlmostEqual(mat, sp.eye(5).todense()) # Parameter size = (5, 4) param = Parameter(*size) param.value = np.ones(size) A = create_param(param, size) coeffs = get_coefficients(A) assert len(coeffs) == 1 id_, mat = coeffs[0] self.assertEqual(mat.shape, (size[0]*size[1], 1)) self.assertItemsAlmostEqual(mat, param.value)
def test_parameters(self): p = Parameter(name='p') self.assertEqual(p.name(), "p") self.assertEqual(p.size, (1,1)) p = Parameter(4, 3, sign="positive") with self.assertRaises(Exception) as cm: p.value = 1 self.assertEqual(str(cm.exception), "Invalid dimensions (1, 1) for Parameter value.") val = -np.ones((4,3)) val[0,0] = 2 p = Parameter(4, 3, sign="positive") with self.assertRaises(Exception) as cm: p.value = val self.assertEqual(str(cm.exception), "Invalid sign for Parameter value.") p = Parameter(4, 3, sign="negative") with self.assertRaises(Exception) as cm: p.value = val self.assertEqual(str(cm.exception), "Invalid sign for Parameter value.") # No error for unknown sign. p = Parameter(4, 3) p.value = val # Initialize a parameter with a value. p = Parameter(value=10) self.assertEqual(p.value, 10) with self.assertRaises(Exception) as cm: p = Parameter(2, 1, sign="negative", value=[2,1]) self.assertEqual(str(cm.exception), "Invalid sign for Parameter value.") with self.assertRaises(Exception) as cm: p = Parameter(4, 3, sign="positive", value=[1,2]) self.assertEqual(str(cm.exception), "Invalid dimensions (2, 1) for Parameter value.") # Test repr. p = Parameter(4, 3, sign="negative") self.assertEqual(repr(p), 'Parameter(4, 3, sign="NEGATIVE")')
def test_quad_form(self) -> None: """Test quad_form atom. """ P = Parameter((2, 2), symmetric=True) expr = cp.quad_form(self.x, P) assert not expr.is_dcp()
def test_readme_examples(self): import cvxopt import numpy # Problem data. m = 30 n = 20 A = cvxopt.normal(m,n) b = cvxopt.normal(m) # Construct the problem. x = Variable(n) objective = Minimize(sum(square(A*x - b))) constraints = [0 <= x, x <= 1] p = Problem(objective, constraints) # The optimal objective is returned by p.solve(). result = p.solve() # The optimal value for x is stored in x.value. print x.value # The optimal Lagrange multiplier for a constraint # is stored in constraint.dual_value. print constraints[0].dual_value #################################################### # Scalar variable. a = Variable() # Column vector variable of length 5. x = Variable(5) # Matrix variable with 4 rows and 7 columns. A = Variable(4,7) #################################################### # Positive scalar parameter. m = Parameter(sign="positive") # Column vector parameter with unknown sign (by default). c = Parameter(5) # Matrix parameter with negative entries. G = Parameter(4,7,sign="negative") # Assigns a constant value to G. G.value = -numpy.ones((4,7)) # Raises an error for assigning a value with invalid sign. with self.assertRaises(Exception) as cm: G.value = numpy.ones((4,7)) self.assertEqual(str(cm.exception), "Invalid sign for Parameter value.") #################################################### a = Variable() x = Variable(5) # expr is an Expression object after each assignment. expr = 2*x expr = expr - a expr = sum(expr) + norm2(x) #################################################### import numpy as np import cvxopt from multiprocessing import Pool # Problem data. n = 10 m = 5 A = cvxopt.normal(n,m) b = cvxopt.normal(n) gamma = Parameter(sign="positive") # Construct the problem. x = Variable(m) objective = Minimize(sum(square(A*x - b)) + gamma*norm1(x)) p = Problem(objective) # Assign a value to gamma and find the optimal x. def get_x(gamma_value): gamma.value = gamma_value result = p.solve() return x.value gammas = np.logspace(-1, 2, num=2) # Serial computation. x_values = [get_x(value) for value in gammas] #################################################### n = 10 mu = cvxopt.normal(1, n) sigma = cvxopt.normal(n,n) sigma = sigma.T*sigma gamma = Parameter(sign="positive") gamma.value = 1 x = Variable(n) # Constants: # mu is the vector of expected returns. # sigma is the covariance matrix. # gamma is a Parameter that trades off risk and return. # Variables: # x is a vector of stock holdings as fractions of total assets. expected_return = mu*x risk = quad_form(x, sigma) objective = Maximize(expected_return - gamma*risk) p = Problem(objective, [sum(x) == 1]) result = p.solve() # The optimal expected return. print expected_return.value # The optimal risk. print risk.value # # Risk return tradeoff curve # def test_risk_return_tradeoff(self): # from math import sqrt # from cvxopt import matrix # from cvxopt.blas import dot # from cvxopt.solvers import qp, options # import scipy # n = 4 # S = matrix( [[ 4e-2, 6e-3, -4e-3, 0.0 ], # [ 6e-3, 1e-2, 0.0, 0.0 ], # [-4e-3, 0.0, 2.5e-3, 0.0 ], # [ 0.0, 0.0, 0.0, 0.0 ]] ) # pbar = matrix([.12, .10, .07, .03]) # N = 100 # # CVXPY # Sroot = numpy.asmatrix(scipy.linalg.sqrtm(S)) # x = Variable(n, name='x') # mu = Parameter(name='mu') # mu.value = 1 # TODO Parameter("positive") # objective = Minimize(-pbar*x + mu*quad_over_lin(Sroot*x,1)) # constraints = [sum(x) == 1, x >= 0] # p = Problem(objective, constraints) # mus = [ 10**(5.0*t/N-1.0) for t in range(N) ] # xs = [] # for mu_val in mus: # mu.value = mu_val # p.solve() # xs.append(x.value) # returns = [ dot(pbar,x) for x in xs ] # risks = [ sqrt(dot(x, S*x)) for x in xs ] # # QP solver
def test_parameters(self): p = Parameter(name='p') self.assertEqual(p.name(), "p") self.assertEqual(p.size, (1, 1)) p = Parameter(4, 3, sign="positive") with self.assertRaises(Exception) as cm: p.value = 1 self.assertEqual(str(cm.exception), "Invalid dimensions (1, 1) for Parameter value.") val = -np.ones((4, 3)) val[0, 0] = 2 p = Parameter(4, 3, sign="positive") with self.assertRaises(Exception) as cm: p.value = val self.assertEqual(str(cm.exception), "Invalid sign for Parameter value.") p = Parameter(4, 3, sign="negative") with self.assertRaises(Exception) as cm: p.value = val self.assertEqual(str(cm.exception), "Invalid sign for Parameter value.") # No error for unknown sign. p = Parameter(4, 3) p.value = val # Initialize a parameter with a value. p = Parameter(value=10) self.assertEqual(p.value, 10) # Test assigning None. p.value = 10 p.value = None assert p.value is None with self.assertRaises(Exception) as cm: p = Parameter(2, 1, sign="negative", value=[2, 1]) self.assertEqual(str(cm.exception), "Invalid sign for Parameter value.") with self.assertRaises(Exception) as cm: p = Parameter(4, 3, sign="positive", value=[1, 2]) self.assertEqual(str(cm.exception), "Invalid dimensions (2, 1) for Parameter value.") # Test repr. p = Parameter(4, 3, sign="negative") self.assertEqual(repr(p), 'Parameter(4, 3, sign="NEGATIVE")')
def test_parameters(self): p = Parameter(name='p') self.assertEqual(p.name(), "p") self.assertEqual(p.size, (1, 1)) p = Parameter(4, 3, sign="positive") with self.assertRaises(Exception) as cm: p.value = 1 self.assertEqual(str(cm.exception), "Invalid dimensions (1,1) for Parameter value.") val = -np.ones((4, 3)) val[0, 0] = 2 p = Parameter(4, 3, sign="positive") with self.assertRaises(Exception) as cm: p.value = val self.assertEqual(str(cm.exception), "Invalid sign for Parameter value.") p = Parameter(4, 3, sign="negative") with self.assertRaises(Exception) as cm: p.value = val self.assertEqual(str(cm.exception), "Invalid sign for Parameter value.") # No error for unknown sign. p = Parameter(4, 3) p.value = val
def test_parameter_promotion(self): a = Parameter() exp = [[1,2],[3,4]]*a a.value = 2 assert not (exp.value - 2*numpy.array([[1,2],[3,4]]).T).any()
def test_quad_form(self): """Test quad_form atom. """ P = Parameter((2, 2)) expr = cp.quad_form(self.x, P) assert not expr.is_dcp()
def test_parameters(self): p = Parameter(name='p') self.assertEqual(p.name(), "p") self.assertEqual(p.size, (1,1))
def test_index(self): """Test the get_coefficients function for index. """ size = (5, 4) # Eye key = (slice(0,2,None), slice(0,2,None)) x = create_var(size) expr = index(x, (2, 2), key) coeffs = get_coefficients(expr) assert len(coeffs) == 1 id_, mat = coeffs[0] self.assertEqual(id_, x.data) self.assertEqual(mat.shape, (4, 20)) test_mat = np.mat(range(20)).T self.assertItemsAlmostEqual((mat*test_mat).reshape((2, 2), order='F'), test_mat.reshape(size, order='F')[key]) # Eye with scalar mult. key = (slice(0,2,None), slice(0,2,None)) x = create_var(size) A = create_const(5, (1, 1)) expr = mul_expr(A, x, size) expr = index(expr, (2, 2), key) coeffs = get_coefficients(expr) assert len(coeffs) == 1 id_, mat = coeffs[0] test_mat = np.mat(range(20)).T self.assertItemsAlmostEqual((mat*test_mat).reshape((2, 2), order='F'), 5*test_mat.reshape(size, order='F')[key]) # Promoted key = (slice(0,2,None), slice(0,2,None)) x = create_var((1, 1)) value = np.array(range(20)).reshape(size) A = create_const(value, size) prom_x = promote(x, (size[1], 1)) expr = mul_expr(A, diag_vec(prom_x), size) expr = index(expr, (2, 2), key) coeffs = get_coefficients(expr) assert len(coeffs) == 1 id_, mat = coeffs[0] self.assertEqual(mat.shape, (4, 1)) self.assertItemsAlmostEqual(mat, value[key]) # Normal size = (5, 5) key = (slice(0,2,None), slice(0,1,None)) x = create_var((5, 1)) A = create_const(np.ones(size), size) expr = mul_expr(A, x, (5, 1)) expr = index(expr, (2, 1), key) coeffs = get_coefficients(expr) assert len(coeffs) == 1 id_, mat = coeffs[0] self.assertEqual(mat.shape, (2, 5)) self.assertItemsAlmostEqual(mat.todense(), A.data[slice(0,2,None)]) # Blocks size = (5, 5) key = (slice(0,2,None), slice(0,2,None)) x = create_var(size) value = np.array(range(25)).reshape(size) A = create_const(value, size) expr = mul_expr(A, x, size) expr = index(expr, (2, 2), key) coeffs = get_coefficients(expr) assert len(coeffs) == 1 id_, mat = coeffs[0] self.assertEqual(mat.shape, (4, 25)) test_mat = np.mat(range(25)).T self.assertItemsAlmostEqual((mat*test_mat).reshape((2, 2), order='F'), (A.data*test_mat.reshape(size, order='F'))[key]) # Scalar constant size = (1, 1) A = create_const(5, size) key = (slice(0,1,None), slice(0,1,None)) expr = index(A, (1, 1), key) coeffs = get_coefficients(expr) assert len(coeffs) == 1 id_, mat = coeffs[0] self.assertEqual(intf.size(mat), (1, 1)) self.assertEqual(mat, 5) # Dense constant size = (5, 4) key = (slice(0,2,None), slice(0,1,None)) value = np.array(range(20)).reshape(size) A = create_const(value, size) expr = index(A, (2, 1), key) coeffs = get_coefficients(expr) assert len(coeffs) == 1 id_, mat = coeffs[0] self.assertEqual(mat.shape, (2, 1)) self.assertItemsAlmostEqual(mat, value[key]) # Sparse constant size = (5, 5) key = (slice(0,2,None), slice(0,1,None)) A = create_const(sp.eye(5), size) expr = index(A, (2, 1), key) coeffs = get_coefficients(expr) assert len(coeffs) == 1 id_, mat = coeffs[0] self.assertEqual(mat.shape, (2, 1)) self.assertItemsAlmostEqual(mat, sp.eye(5).todense()[key]) # Parameter size = (5, 4) key = (slice(0,2,None), slice(0,1,None)) param = Parameter(*size) value = np.array(range(20)).reshape(size) param.value = value A = create_param(param, size) expr = index(A, (2, 1), key) coeffs = get_coefficients(expr) assert len(coeffs) == 1 id_, mat = coeffs[0] self.assertEqual(mat.shape, (2, 1)) self.assertItemsAlmostEqual(mat, param.value[key])