def test_constant_copy(self): """Test the copy function for Constants. """ x = Constant(2) y = x.copy() self.assertEqual(y.size, (1, 1)) self.assertEqual(y.value, 2)
def test_constants(self): c = Constant(2) self.assertEqual(c.name(), str(2)) c = Constant(2) self.assertEqual(c.value, 2) self.assertEqual(c.size, (1,1)) self.assertEqual(c.curvature, u.Curvature.CONSTANT_KEY) self.assertEqual(c.sign, u.Sign.POSITIVE_KEY) self.assertEqual(Constant(-2).sign, u.Sign.NEGATIVE_KEY) self.assertEqual(Constant(0).sign, u.Sign.ZERO_KEY) self.assertEqual(c.canonical_form[0].size, (1,1)) self.assertEqual(c.canonical_form[1], []) # coeffs = c.coefficients() # self.assertEqual(coeffs.keys(), [s.CONSTANT]) # self.assertEqual(coeffs[s.CONSTANT], [2]) # Test the sign. c = Constant([[2], [2]]) self.assertEqual(c.size, (1, 2)) self.assertEqual(c.sign, u.Sign.UNKNOWN_KEY) # Test sign of a complex expression. c = Constant([1, 2]) A = Constant([[1,1],[1,1]]) exp = c.T*A*c self.assertEqual(exp.sign, u.Sign.UNKNOWN_KEY) self.assertEqual((c.T*c).sign, u.Sign.UNKNOWN_KEY) exp = c.T.T self.assertEqual(exp.sign, u.Sign.UNKNOWN_KEY) exp = c.T*self.A self.assertEqual(exp.sign, u.Sign.UNKNOWN_KEY)
def test_add_expression(self): # Vectors c = Constant([2,2]) exp = self.x + c self.assertEqual(exp.curvature, u.Curvature.AFFINE) self.assertEqual(exp.sign, u.Sign.UNKNOWN) self.assertEqual(exp.canonicalize()[0].size, (2,1)) self.assertEqual(exp.canonicalize()[1], []) self.assertEqual(exp.name(), self.x.name() + " + " + c.name()) self.assertEqual(exp.size, (2,1)) z = Variable(2, name='z') exp = exp + z + self.x with self.assertRaises(Exception) as cm: (self.x + self.y) self.assertEqual(str(cm.exception), "Incompatible dimensions.") # Matrices exp = self.A + self.B self.assertEqual(exp.curvature, u.Curvature.AFFINE) self.assertEqual(exp.size, (2,2)) with self.assertRaises(Exception) as cm: (self.A + self.C) self.assertEqual(str(cm.exception), "Incompatible dimensions.")
def setUp(self): self.a = Variable() self.x = Variable(2, name='x') self.y = Variable(2, name='y') self.A = Variable(2,2) self.c = Constant(3) self.C = Constant([[1, 2], [1, 2]])
def test_constants(self): c = Constant(2) self.assertEqual(c.name(), str(2)) c = Constant(2, name="c") self.assertEqual(c.name(), "c") self.assertEqual(c.value, 2) self.assertEqual(c.size, (1,1)) self.assertEqual(c.curvature, u.Curvature.CONSTANT) self.assertEqual(c.sign, u.Sign.POSITIVE) self.assertEqual(Constant(-2).sign, u.Sign.NEGATIVE) self.assertEqual(Constant(0).sign, u.Sign.ZERO) self.assertEqual(c.canonicalize()[0].size, (1,1)) self.assertEqual(c.canonicalize()[1], []) coeffs = c.coefficients(self.intf) self.assertEqual(coeffs.keys(), [Constant]) self.assertEqual(coeffs[Constant], 2) # Test the sign. c = Constant([[2],[2]]) self.assertEqual(c.size, (1,2)) self.assertEqual(c.sign.neg_mat.value.shape, (1,2)) # Test sign of a complex expression. c = Constant([1, 2]) A = Constant([[1,1],[1,1]]) exp = c.T*A*c self.assertEqual(exp.sign, u.Sign.POSITIVE) self.assertEqual((c.T*c).sign, u.Sign.POSITIVE) exp = c.T.T self.assertEqual(exp.sign.pos_mat.value.ndim, 2) exp = c.T*self.A self.assertEqual(exp.sign.pos_mat.value.ndim, 2)
def test_matmul_expression(self): """Test matmul function, corresponding to .__matmul__( operator. """ if PY35: # Vectors c = Constant([[2], [2]]) exp = c.__matmul__(self.x) self.assertEqual(exp.curvature, s.AFFINE) self.assertEqual(exp.sign, s.UNKNOWN) self.assertEqual(exp.canonical_form[0].size, (1, 1)) self.assertEqual(exp.canonical_form[1], []) # self.assertEqual(exp.name(), c.name() + " .__matmul__( " + self.x.name()) self.assertEqual(exp.size, (1, 1)) with self.assertRaises(Exception) as cm: self.x.__matmul__(2) self.assertEqual(str(cm.exception), "Scalar operands are not allowed, use '*' instead") with self.assertRaises(Exception) as cm: (self.x.__matmul__(np.array([2, 2, 3]))) self.assertEqual(str(cm.exception), "Incompatible dimensions (2, 1) (3, 1)") # Matrices with self.assertRaises(Exception) as cm: Constant([[2, 1], [2, 2]]) .__matmul__(self.C) self.assertEqual(str(cm.exception), "Incompatible dimensions (2, 2) (3, 2)") # Affine times affine is okay with warnings.catch_warnings(): warnings.simplefilter("ignore") q = self.A .__matmul__(self.B) self.assertTrue(q.is_quadratic()) # Nonaffine times nonconstant raises error with warnings.catch_warnings(): warnings.simplefilter("ignore") with self.assertRaises(Exception) as cm: (self.A.__matmul__(self.B).__matmul__(self.A)) self.assertEqual(str(cm.exception), "Cannot multiply UNKNOWN and AFFINE.") # Constant expressions T = Constant([[1, 2, 3], [3, 5, 5]]) exp = (T + T) .__matmul__(self.B) self.assertEqual(exp.curvature, s.AFFINE) self.assertEqual(exp.size, (3, 2)) # Expression that would break sign multiplication without promotion. c = Constant([[2], [2], [-2]]) exp = [[1], [2]] + c.__matmul__(self.C) self.assertEqual(exp.sign, s.UNKNOWN) else: pass
def linearize(expr): """Returns the tangent approximation to the expression. Gives an elementwise lower (upper) bound for convex (concave) expressions. No guarantees for non-DCP expressions. Returns None if cannot be linearized. Args: expr: An expression. Returns: An affine expression or None. """ expr = Constant.cast_to_const(expr) if expr.is_affine(): return expr else: tangent = expr.value if tangent is None: raise ValueError( "Cannot linearize non-affine expression with missing variable values." ) grad_map = expr.grad for var in expr.variables(): if grad_map[var] is None: return None elif var.is_matrix(): flattened = Constant(grad_map[var]).T*vec(var - var.value) tangent = tangent + reshape(flattened, *expr.size) else: tangent = tangent + Constant(grad_map[var]).T*(var - var.value) return tangent
def quad_form(x, P): """ Alias for :math:`x^T P x`. """ x, P = map(Expression.cast_to_const, (x, P)) # Check dimensions. n = P.size[0] if P.size[1] != n or x.size != (n, 1): raise Exception("Invalid dimensions for arguments.") if x.is_constant(): return x.T * P * x elif P.is_constant(): P = intf.DEFAULT_NP_INTF.const_to_matrix(P.value) # Force symmetry P = (P + P.T) / 2.0 scale, M1, M2 = _decomp_quad(P) ret = 0 if M1.size > 0: ret += scale * sum_squares(Constant(M1.T) * x) if M2.size > 0: ret -= scale * sum_squares(Constant(M2.T) * x) return ret else: raise Exception("At least one argument to quad_form must be constant.")
def mi_lp_3() -> SolverTestHelper: # infeasible (but relaxable) test case x = cp.Variable(4, boolean=True) from cvxpy.expressions.constants import Constant objective = cp.Maximize(Constant(1)) constraints = [ x[0] + x[1] + x[2] + x[3] <= 2, x[0] + x[1] + x[2] + x[3] >= 2, x[0] + x[1] <= 1, x[0] + x[2] <= 1, x[0] + x[3] <= 1, x[2] + x[3] <= 1, x[1] + x[3] <= 1, x[1] + x[2] <= 1 ] obj_pair = (objective, -np.inf) con_pairs = [(c, None) for c in constraints] var_pairs = [(x, None)] sth = SolverTestHelper(obj_pair, var_pairs, con_pairs) return sth
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_none_idx(self): """Test None as index. """ expr = self.a[None, None] self.assertEqual(expr.shape, (1, 1)) expr = self.x[:, None] self.assertEqual(expr.shape, (2, 1)) expr = self.x[None, :] self.assertEqual(expr.shape, (1, 2)) expr = Constant([1, 2])[None, :] self.assertEqual(expr.shape, (1, 2)) self.assertItemsAlmostEqual(expr.value, [1, 2])
def canonicalize_expr(self, expr, args): if isinstance(expr, Expression) and not expr.variables(): # Parameterized expressions are evaluated in a subsequent # reduction. if expr.parameters(): rows, cols = expr.shape param = CallbackParam(lambda: expr.value, (rows, cols)) return param, [] # Non-parameterized expressions are evaluated immediately. else: return Constant(expr.value), [] elif type(expr) in self.canon_methods: return self.canon_methods[type(expr)](expr, args) else: return expr.copy(args), []
def test_mul_expression(self): # Vectors c = Constant([[2],[2]]) exp = c*self.x self.assertEqual(exp.curvature, u.Curvature.AFFINE) self.assertEqual((c[0]*self.x).sign, u.Sign.UNKNOWN) self.assertEqual(exp.canonicalize()[0].size, (1,1)) self.assertEqual(exp.canonicalize()[1], []) self.assertEqual(exp.name(), c.name() + " * " + self.x.name()) self.assertEqual(exp.size, (1,1)) with self.assertRaises(Exception) as cm: ([2,2,3]*self.x) const_name = Constant([2,2,3]).name() self.assertEqual(str(cm.exception), "Incompatible dimensions.") # Matrices with self.assertRaises(Exception) as cm: Constant([[2, 1],[2, 2]]) * self.C self.assertEqual(str(cm.exception), "Incompatible dimensions.") with self.assertRaises(Exception) as cm: (self.A * self.B) self.assertEqual(str(cm.exception), "Cannot multiply two non-constants.") # Constant expressions T = Constant([[1,2,3],[3,5,5]]) exp = (T + T) * self.B self.assertEqual(exp.curvature, u.Curvature.AFFINE) self.assertEqual(exp.size, (3,2)) # Expression that would break sign multiplication without promotion. c = Constant([[2],[2],[-2]]) exp = [[1],[2]] + c*self.C self.assertEqual(exp.sign.pos_mat.value.shape, (1,2))
def _grad(self, values): """Gives the (sub/super)gradient of the atom w.r.t. each argument. Matrix expressions are vectorized, so the gradient is a matrix. Args: values: A list of numeric values for the arguments. Returns: A list of SciPy CSC sparse matrices or None. """ # TODO should be a simple function in cvxcore for this. # Make a fake lin op tree for the function. fake_args = [] var_offsets = {} offset = 0 for idx, arg in enumerate(self.args): if arg.is_constant(): fake_args += [Constant(arg.value).canonical_form[0]] else: fake_args += [lu.create_var(arg.shape, idx)] var_offsets[idx] = offset offset += arg.size fake_expr, _ = self.graph_implementation(fake_args, self.shape, self.get_data()) # Get the matrix representation of the function. V, I, J, _ = canonInterface.get_problem_matrix( [fake_expr], var_offsets, None ) shape = (offset, self.size) stacked_grad = sp.csc_matrix((V, (J, I)), shape=shape) # Break up into per argument matrices. grad_list = [] start = 0 for arg in self.args: if arg.is_constant(): grad_shape = (arg.size, shape[1]) if grad_shape == (1, 1): grad_list += [0] else: grad_list += [sp.coo_matrix(grad_shape, dtype='float64')] else: stop = start + arg.size grad_list += [stacked_grad[start:stop, :]] start = stop return grad_list
def test_imag(self) -> None: """Test imag. """ A = np.ones((2, 2)) expr = Constant(A) + 2j*Constant(A) expr = cvx.imag(expr) assert expr.is_real() assert not expr.is_complex() assert not expr.is_imag() self.assertItemsAlmostEqual(expr.value, 2*A)
def test_conj(self): """Test imag. """ A = np.ones((2, 2)) expr = Constant(A) + 1j*Constant(A) expr = cvx.conj(expr) assert not expr.is_real() assert expr.is_complex() assert not expr.is_imag() self.assertItemsAlmostEqual(expr.value, A - 1j*A)
def test_real(self): """Test real. """ A = np.ones((2, 2)) expr = Constant(A) + 1j*Constant(A) expr = cvx.real(expr) assert expr.is_real() assert not expr.is_complex() assert not expr.is_imag() self.assertItemsAlmostEqual(expr.value, A) x = Variable(complex=True) expr = cvx.imag(x) + cvx.real(x) assert expr.is_real()
def power_canon(expr, args): affine_expr = args[0] p = expr.p if expr.is_constant(): return Constant(expr.value), [] elif p == 0: return np.ones(affine_expr.shape), [] elif p == 1: return affine_expr, [] elif p == 2: if isinstance(affine_expr, Variable): return SymbolicQuadForm(affine_expr, np.eye(affine_expr.size), expr), [] else: t = Variable(affine_expr.shape) return SymbolicQuadForm(t, np.eye(t.size), expr), [affine_expr == t] raise ValueError("non-constant quadratic forms can't be raised to a power " "greater than 2.")
def quad_form(x, P): """ Alias for :math:`x^T P x`. """ x, P = map(Expression.cast_to_const, (x, P)) # Check dimensions. n = P.size[0] if P.size[1] != n or x.size != (n, 1): raise Exception("Invalid dimensions for arguments.") if x.is_constant(): return x.T * P * x elif P.is_constant(): np_intf = intf.get_matrix_interface(np.ndarray) P = np_intf.const_to_matrix(P.value) sgn, scale, M = _decomp_quad(P) return sgn * scale * square(norm(Constant(M.T) * x)) else: raise Exception("At least one argument to quad_form must be constant.")
def pnorm_canon(expr, args): x = args[0] p = expr.p axis = expr.axis shape = expr.shape t = Variable(shape) if p == 2: if axis is None: assert shape == tuple() return t, [SOC(t, vec(x))] else: return t, [SOC(vec(t), x, axis)] # we need an absolute value constraint for the symmetric convex branches # (p > 1) constraints = [] if p > 1: # TODO(akshayka): Express this more naturally (recursively), in terms # of the other atoms abs_expr = abs(x) abs_x, abs_constraints = abs_canon(abs_expr, abs_expr.args) x = abs_x constraints += abs_constraints # now, we take care of the remaining convex and concave branches # to create the rational powers, we need a new variable, r, and # the constraint sum(r) == t r = Variable(x.shape) constraints += [sum(r) == t] # todo: no need to run gm_constr to form the tree each time. # we only need to form the tree once promoted_t = Constant(np.ones(x.shape)) * t p = Fraction(p) if p < 0: constraints += gm_constrs(promoted_t, [x, r], (-p / (1 - p), 1 / (1 - p))) if 0 < p < 1: constraints += gm_constrs(r, [x, promoted_t], (p, 1 - p)) if p > 1: constraints += gm_constrs(x, [r, promoted_t], (1 / p, 1 - 1 / p)) return t, constraints
def test_constant_atoms(): tests = [] for atom_list, objective_type in atoms: for atom, size, args, obj_val in atom_list: 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])) yield (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 == Maximize: objective = -objective new_obj_val = -new_obj_val problem = Problem(objective, constraints) yield (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]) yield (run_atom, atom, Problem(objective), prob_val, solver)
def canonicalize(self): """Represent the atom as an affine objective and conic constraints. """ # Constant atoms are treated as a leaf. if self.is_constant() and not self.parameters(): # Non-parameterized expressions are evaluated immediately. return Constant(self.value).canonical_form else: arg_objs = [] constraints = [] for arg in self.args: obj, constr = arg.canonical_form arg_objs.append(obj) constraints += constr # Special info required by the graph implementation. data = self.get_data() graph_obj, graph_constr = self.graph_implementation( arg_objs, self.shape, data) return graph_obj, constraints + graph_constr
def test_vector_lp(self): c = matrix([1, 2]) p = Problem(Minimize(c.T * self.x), [self.x >= c]) result = p.solve() self.assertAlmostEqual(result, 5) self.assertItemsAlmostEqual(self.x.value, [1, 2]) A = matrix([[3, 5], [1, 2]]) I = Constant([[1, 0], [0, 1]]) p = Problem(Minimize(c.T * self.x + self.a), [ A * self.x >= [-1, 1], 4 * I * self.z == self.x, self.z >= [2, 2], self.a >= 2 ]) result = p.solve() self.assertAlmostEqual(result, 26, places=3) obj = c.T * self.x.value + self.a.value self.assertAlmostEqual(obj[0, 0], result) self.assertItemsAlmostEqual(self.x.value, [8, 8], places=3) self.assertItemsAlmostEqual(self.z.value, [2, 2], places=3)
def quad_canon(expr, real_args, imag_args, real2imag): """Convert quad_form to real. """ if imag_args[0] is None: vec = real_args[0] matrix = real_args[1] elif real_args[0] is None: vec = imag_args[0] matrix = real_args[1] else: vec = vstack([at_least_2D(real_args[0]), at_least_2D(imag_args[0])]) if real_args[1] is None: real_args[1] = np.zeros(imag_args[1].shape) elif imag_args[1] is None: imag_args[1] = np.zeros(real_args[1].shape) matrix = bmat([[real_args[1], -imag_args[1]], [imag_args[1], real_args[1]]]) # HACK TODO matrix = Constant(matrix.value) return expr.copy([vec, matrix]), None
def canonicalize_expr(self, expr, real_args, imag_args, real2imag, leaf_map): if isinstance(expr, Expression) and not expr.variables(): # Parameterized expressions are evaluated in a subsequent # reduction. if expr.parameters(): return NotImplemented # Non-parameterized expressions are evaluated immediately. else: return elim_cplx_methods[Constant](Constant(expr.value), real_args, imag_args, real2imag) elif type(expr) in elim_cplx_methods: # Only canonicalize a variable/constant/parameter once. if len(expr.args) == 0 and expr in leaf_map: return leaf_map[expr] result = elim_cplx_methods[type(expr)](expr, real_args, imag_args, real2imag) if len(expr.args) == 0: leaf_map[expr] = result return result else: assert all(v is None for v in imag_args) return expr.copy(real_args), None
def test_add_expression(self): # Vectors c = Constant([2, 2]) exp = self.x + c 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(), self.x.name() + " + " + c.name()) self.assertEqual(exp.size, (2, 1)) z = Variable(2, name='z') exp = exp + z + self.x with self.assertRaises(Exception) as cm: (self.x + self.y) self.assertEqual(str(cm.exception), "Incompatible dimensions (2, 1) (3, 1)") # Matrices exp = self.A + self.B self.assertEqual(exp.curvature, u.Curvature.AFFINE_KEY) self.assertEqual(exp.size, (2, 2)) with self.assertRaises(Exception) as cm: (self.A + self.C) self.assertEqual(str(cm.exception), "Incompatible dimensions (2, 2) (3, 2)") with self.assertRaises(Exception) as cm: AddExpression([self.A, self.C]) self.assertEqual(str(cm.exception), "Incompatible dimensions (2, 2) (3, 2)") # Test that sum is flattened. exp = self.x + c + self.x self.assertEqual(len(exp.args), 3) # Test repr. self.assertEqual(repr(exp), "Expression(AFFINE, UNKNOWN, (2, 1))")
def test_constants(self): c = Constant(2) self.assertEqual(c.name(), str(2)) c = Constant(2, name="c") self.assertEqual(c.name(), "c") self.assertEqual(c.value, 2) self.assertEqual(c.size, (1,1)) self.assertEqual(c.curvature, u.Curvature.CONSTANT) self.assertEqual(c.sign, u.Sign.POSITIVE) self.assertEqual(Constant(-2).sign, u.Sign.NEGATIVE) self.assertEqual(Constant(0).sign, u.Sign.ZERO) self.assertEqual(c.canonicalize()[0].size, (1,1)) self.assertEqual(c.canonicalize()[1], []) coeffs = c.coefficients(self.intf) self.assertEqual(coeffs.keys(), [s.CONSTANT]) self.assertEqual(coeffs[s.CONSTANT], 2) # Test the sign. c = Constant([[2],[2]]) self.assertEqual(c.size, (1,2)) self.assertEqual(c.sign.neg_mat.value.shape, (1,2))
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] if len(size) != 0: objective = objective_type(atom(*const_args)[indexer]) else: objective = objective_type(atom(*const_args)) problem = Problem(objective) 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) if len(size) != 0: objective = objective_type(atom(*variables)[indexer]) else: objective = objective_type(atom(*variables)) problem = Problem(objective, constraints) run_atom(atom, problem, prob_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) if len(size) != 0: objective = objective_type(atom(*parameters)[indexer]) else: objective = objective_type(atom(*parameters)) run_atom(atom, Problem(objective), prob_val, solver)
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)
def test_add_expression(self): # Vectors c = Constant([2, 2]) exp = self.x + c 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(), self.x.name() + " + " + c.name()) self.assertEqual(exp.shape, (2, )) z = Variable(2, name='z') exp = exp + z + self.x # Incompatible dimensions with self.assertRaises(ValueError): (self.x + self.y) # Matrices exp = self.A + self.B self.assertEqual(exp.curvature, s.AFFINE) self.assertEqual(exp.shape, (2, 2)) # Incompatible dimensions with self.assertRaises(ValueError): (self.A + self.C) # Incompatible dimensions with self.assertRaises(ValueError): AddExpression([self.A, self.C]) # Test that sum is flattened. exp = self.x + c + self.x self.assertEqual(len(exp.args), 3) # Test repr. self.assertEqual(repr(exp), "Expression(AFFINE, UNKNOWN, (2,))")
def power_canon(expr, args): x = args[0] p = expr.p w = expr.w if p == 1: return x, [] shape = expr.shape ones = Constant(np.ones(shape)) if p == 0: return ones, [] else: t = Variable(shape) # TODO(akshayka): gm_constrs requires each of its inputs to be a Variable; # is this something that we want to change? if 0 < p < 1: return t, gm_constrs(t, [x, ones], w) elif p > 1: return t, gm_constrs(x, [t, ones], w) elif p < 0: return t, gm_constrs(ones, [x, t], w) else: raise NotImplementedError('This power is not yet supported.')
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_constants(self): c = Constant(2) self.assertEqual(c.name(), str(2)) c = Constant(2) self.assertEqual(c.value, 2) self.assertEqual(c.size, (1, 1)) self.assertEqual(c.curvature, s.CONSTANT) self.assertEqual(c.sign, s.POSITIVE) self.assertEqual(Constant(-2).sign, s.NEGATIVE) self.assertEqual(Constant(0).sign, s.ZERO) self.assertEqual(c.canonical_form[0].size, (1, 1)) self.assertEqual(c.canonical_form[1], []) # coeffs = c.coefficients() # self.assertEqual(coeffs.keys(), [s.CONSTANT]) # self.assertEqual(coeffs[s.CONSTANT], [2]) # Test the sign. c = Constant([[2], [2]]) self.assertEqual(c.size, (1, 2)) self.assertEqual(c.sign, s.POSITIVE) self.assertEqual((-c).sign, s.NEGATIVE) self.assertEqual((0*c).sign, s.ZERO) c = Constant([[2], [-2]]) self.assertEqual(c.sign, s.UNKNOWN) # Test sign of a complex expression. c = Constant([1, 2]) A = Constant([[1, 1], [1, 1]]) exp = c.T*A*c self.assertEqual(exp.sign, s.POSITIVE) self.assertEqual((c.T*c).sign, s.POSITIVE) exp = c.T.T self.assertEqual(exp.sign, s.POSITIVE) exp = c.T*self.A self.assertEqual(exp.sign, s.UNKNOWN) # Test repr. self.assertEqual(repr(c), "Constant(CONSTANT, POSITIVE, (2, 1))")
def test_round_attr(self): """Test rounding for attributes. """ # Nonpos v = Variable(1, nonpos=True) self.assertAlmostEqual(v.project(1), 0) v = Variable(2, nonpos=True) self.assertItemsAlmostEqual(v.project(np.array([1, -1])), [0, -1]) # Nonneg v = Variable(1, nonneg=True) self.assertAlmostEqual(v.project(-1), 0) v = Variable(2, nonneg=True) self.assertItemsAlmostEqual(v.project(np.array([1, -1])), [1, 0]) # Boolean v = Variable((2, 2), boolean=True) self.assertItemsAlmostEqual(v.project(np.array([[1, -1], [1, 0]]).T), [1, 0, 1, 0]) # Integer v = Variable((2, 2), integer=True) self.assertItemsAlmostEqual(v.project(np.array([[1, -1.6], [1, 0]]).T), [1, -2, 1, 0]) # Symmetric v = Variable((2, 2), symmetric=True) self.assertItemsAlmostEqual(v.project(np.array([[1, -1], [1, 0]])), [1, 0, 0, 0]) # PSD v = Variable((2, 2), PSD=True) self.assertItemsAlmostEqual(v.project(np.array([[1, -1], [1, -1]])), [1, 0, 0, 0]) # NSD v = Variable((2, 2), NSD=True) self.assertItemsAlmostEqual(v.project(np.array([[1, -1], [1, -1]])), [0, 0, 0, -1]) # diag v = Variable((2, 2), diag=True) self.assertItemsAlmostEqual( v.project(np.array([[1, -1], [1, 0]])).todense(), [1, 0, 0, 0]) # Hermitian v = Variable((2, 2), hermitian=True) self.assertItemsAlmostEqual(v.project(np.array([[1, -1j], [1, 0]])), [1, 0.5 + 0.5j, 0.5 - 0.5j, 0]) A = Constant(np.array([[1.0]])) self.assertEqual(A.is_psd(), True) self.assertEqual(A.is_nsd(), False) A = Constant(np.array([[-1.0]])) self.assertEqual(A.is_psd(), False) self.assertEqual(A.is_nsd(), True) A = Constant(np.array([[0.0]])) self.assertEqual(A.is_psd(), True) self.assertEqual(A.is_nsd(), True)
def test_matmul_expression(self): """Test matmul function, corresponding to .__matmul__( operator. """ # Vectors c = Constant([[2], [2]]) exp = c.__matmul__(self.x) self.assertEqual(exp.curvature, s.AFFINE) self.assertEqual(exp.sign, s.UNKNOWN) # self.assertEqual(exp.name(), c.name() + " .__matmul__( " + self.x.name()) self.assertEqual(exp.shape, (1, )) with self.assertRaises(Exception) as cm: self.x.__matmul__(2) self.assertEqual(str(cm.exception), "Scalar operands are not allowed, use '*' instead") # Incompatible dimensions with self.assertRaises(ValueError) as cm: (self.x.__matmul__(np.array([2, 2, 3]))) # Incompatible dimensions with self.assertRaises(Exception) as cm: Constant([[2, 1], [2, 2]]).__matmul__(self.C) # Affine times affine is okay with warnings.catch_warnings(): warnings.simplefilter("ignore") q = self.A.__matmul__(self.B) self.assertTrue(q.is_quadratic()) # # Nonaffine times nonconstant raises error # with warnings.catch_warnings(): # warnings.simplefilter("ignore") # with self.assertRaises(Exception) as cm: # (self.A.__matmul__(self.B).__matmul__(self.A)) # self.assertEqual(str(cm.exception), "Cannot multiply UNKNOWN and AFFINE.") # Constant expressions T = Constant([[1, 2, 3], [3, 5, 5]]) exp = (T + T).__matmul__(self.B) self.assertEqual(exp.curvature, s.AFFINE) self.assertEqual(exp.shape, (3, 2)) # Expression that would break sign multiplication without promotion. c = Constant([[2], [2], [-2]]) exp = [[1], [2]] + c.__matmul__(self.C) self.assertEqual(exp.sign, s.UNKNOWN) # Testing shape. a = Parameter((1, )) x = Variable(shape=(1, )) expr = a.__matmul__(x) self.assertEqual(expr.shape, ()) # Testing shape. a = Parameter((1, )) x = Variable(shape=(1, )) expr = a.__matmul__(x) self.assertEqual(expr.shape, ()) A = Parameter((4, 4)) z = Variable((4, 1)) expr = A.__matmul__(z) self.assertEqual(expr.shape, (4, 1)) v = Variable((1, 1)) col_scalar = Parameter((1, 1)) assert v.shape == col_scalar.shape == col_scalar.T.shape
class test_coefficients(unittest.TestCase): """ Unit tests for the expressions.affine module. """ def setUp(self): self.a = Variable() self.x = Variable(2, name='x') self.y = Variable(2, name='y') self.A = Variable(2,2) self.c = Constant(3) self.C = Constant([[1, 2], [1, 2]]) def test_leaf_coeffs(self): """Test the coefficients for Variables and Constants. """ # Scalars coeffs = self.a.coefficients() self.assertItemsEqual(coeffs.keys(), [self.a]) blocks = coeffs[self.a] self.assertEqual(len(blocks), 1) self.assertEqual(blocks[0], 1) # Vectors coeffs = self.x.coefficients() self.assertItemsEqual(coeffs.keys(), [self.x]) blocks = coeffs[self.x] self.assertEqual(len(blocks), 1) self.assertEqual(blocks[0].size, (2,2)) # Matrices coeffs = self.A.coefficients() self.assertItemsEqual(coeffs.keys(), [self.A]) blocks = coeffs[self.A] self.assertEqual(len(blocks), 2) self.assertEqual(blocks[0].size, (2,4)) # Constants coeffs = self.c.coefficients() self.assertItemsEqual(coeffs.keys(), [s.CONSTANT]) blocks = coeffs[s.CONSTANT] self.assertEqual(len(blocks), 1) self.assertEqual(blocks[0], 3) coeffs = self.C.coefficients() self.assertItemsEqual(coeffs.keys(), [s.CONSTANT]) blocks = coeffs[s.CONSTANT] self.assertEqual(len(blocks), 2) self.assertEqual(blocks[0].size, (2,1)) self.assertEqual(blocks[0][0,0], 1) def test_add(self): """Test adding coefficients. """ coeffs = cu.add(self.x.coefficients(), self.y.coefficients()) self.assertItemsEqual(coeffs.keys(), [self.x, self.y]) blocks = coeffs[self.x] self.assertEqual(len(blocks), 1) self.assertEqual(blocks[0].size, (2,2)) coeffs = cu.add(coeffs, coeffs) self.assertItemsEqual(coeffs.keys(), [self.x, self.y]) blocks = coeffs[self.x] self.assertEqual(len(blocks), 1) self.assertEqual(blocks[0].size, (2,2)) self.assertEqual(blocks[0][0,0], 2) coeffs = cu.add(coeffs, self.C.coefficients()) self.assertItemsEqual(coeffs.keys(), [self.x, self.y, s.CONSTANT]) blocks = coeffs[s.CONSTANT] self.assertEqual(len(blocks), 2) self.assertEqual(blocks[0].size, (2,1)) self.assertEqual(blocks[0][0,0], 1) def test_neg(self): """Test negating coefficients. """ coeffs = cu.neg(self.a.coefficients()) self.assertItemsEqual(coeffs.keys(), [self.a]) blocks = coeffs[self.a] self.assertEqual(len(blocks), 1) self.assertEqual(blocks[0], -1) coeffs = cu.neg(self.A.coefficients()) self.assertItemsEqual(coeffs.keys(), [self.A]) blocks = coeffs[self.A] self.assertEqual(len(blocks), 2) self.assertEqual(blocks[0].size, (2,4)) self.assertEqual(blocks[0][0,0], -1) def test_sub(self): """Test subtracting coefficients. """ coeffs = cu.sub(self.x.coefficients(), self.y.coefficients()) self.assertItemsEqual(coeffs.keys(), [self.x, self.y]) blocks = coeffs[self.y] self.assertEqual(len(blocks), 1) self.assertEqual(blocks[0].size, (2,2)) self.assertEqual(blocks[0][0,0], -1) coeffs = cu.sub(coeffs, self.x.coefficients()) self.assertItemsEqual(coeffs.keys(), [self.x, self.y]) blocks = coeffs[self.x] self.assertEqual(len(blocks), 1) self.assertEqual(blocks[0].size, (2,2)) self.assertEqual(blocks[0][0,0], 0) def test_mul(self): """Test multiplying coefficients. """ coeffs = cu.add(self.x.coefficients(), self.y.coefficients()) coeffs = cu.mul(self.C.coefficients(), coeffs) self.assertItemsEqual(coeffs.keys(), [self.x, self.y]) blocks = coeffs[self.y] self.assertEqual(len(blocks), 1) self.assertEqual(blocks[0].size, (2,2)) self.assertEqual(blocks[0][1,0], 2) # Scalar by Matrix multiplication. coeffs = cu.add(self.x.coefficients(), self.y.coefficients()) coeffs = cu.mul(self.c.coefficients(), coeffs) self.assertItemsEqual(coeffs.keys(), [self.x, self.y]) blocks = coeffs[self.y] self.assertEqual(len(blocks), 1) self.assertEqual(blocks[0].size, (2,2)) self.assertEqual(blocks[0][0,0], 3) # Matrix by Scalar multiplication. coeffs = self.a.coefficients() coeffs = cu.mul(self.C.coefficients(), coeffs) self.assertItemsEqual(coeffs.keys(), [self.a]) blocks = coeffs[self.a] self.assertEqual(len(blocks), 2) self.assertEqual(blocks[0].size, (2,1)) self.assertEqual(blocks[0][1,0], 2) self.assertEqual(blocks[1].size, (2,1)) self.assertEqual(blocks[1][1,0], 2) def test_index(self): """Test indexing/slicing into coefficients. """ # Index. sum_coeffs = cu.add(self.x.coefficients(), self.y.coefficients()) key = ku.validate_key((1, 0), self.x.shape) coeffs = cu.index(sum_coeffs, key) self.assertItemsEqual(coeffs.keys(), [self.x, self.y]) blocks = coeffs[self.y] self.assertEqual(len(blocks), 1) self.assertEqual(blocks[0].size, (1,2)) self.assertEqual(blocks[0][0,0], 0) # Slice. sum_coeffs = cu.add(self.A.coefficients(), self.C.coefficients()) key = ku.validate_key((slice(None, None, None), 1), self.A.shape) coeffs = cu.index(sum_coeffs, key) self.assertItemsEqual(coeffs.keys(), [self.A, s.CONSTANT]) # Variable. blocks = coeffs[self.A] self.assertEqual(len(blocks), 1) self.assertEqual(blocks[0].size, (2,4)) # Constant. blocks = coeffs[s.CONSTANT] self.assertEqual(len(blocks), 1) self.assertEqual(blocks[0].size, (2,1))
from cvxpy.problems.objective import * from cvxpy.problems.problem import Problem from cvxpy.expressions.variables import Variable from cvxpy.expressions.constants import Constant, Parameter import cvxopt import math from nose.tools import assert_raises TOL = 1e-3 v = cvxopt.matrix([-1, 2, -2], tc='d') atoms = [ ( [ (abs([[-5, 2], [-3, 1]]), Constant([[5, 2], [3, 1]])), (exp([[1, 0], [2, -1]]), Constant([[math.e, 1], [math.e**2, 1.0 / math.e]])), #(huber(0.5), 0.25), #(huber(-1.5), 2), (inv_pos([[1, 2], [3, 4]]), Constant([[1, 1.0 / 2], [1.0 / 3, 1.0 / 4]])), (kl_div(math.e, 1), Constant([1])), (kl_div(math.e, math.e), Constant([0])), (lambda_max([[2, 0], [0, 1]]), Constant([2])), (lambda_max([[5, 7], [7, -3]]), Constant([9.06225775])), (log_sum_exp([[5, 7], [0, -3]]), Constant([7.1277708268])), (max([-5, 2], [-3, 1], 0, [-1, 2]), Constant([0, 2])), (max([[-5, 2], [-3, 1]], 0, [[5, 4], [-1, 2]]), Constant([[5, 4], [0, 2]])),
def test_index_expression(self): # Tuple of integers as key. exp = self.x[1, 0] # self.assertEqual(exp.name(), "x[1,0]") self.assertEqual(exp.curvature, u.Curvature.AFFINE_KEY) assert exp.is_affine() self.assertEquals(exp.size, (1, 1)) # coeff = exp.canonical_form[0].coefficients()[self.x][0] # self.assertEqual(coeff[0,1], 1) self.assertEqual(exp.value, None) exp = self.x[1, 0].T # self.assertEqual(exp.name(), "x[1,0]") self.assertEqual(exp.curvature, u.Curvature.AFFINE_KEY) self.assertEquals(exp.size, (1, 1)) with self.assertRaises(Exception) as cm: (self.x[2, 0]) self.assertEqual(str(cm.exception), "Index/slice out of bounds.") # Slicing exp = self.C[0:2, 1] # self.assertEquals(exp.name(), "C[0:2,1]") self.assertEquals(exp.size, (2, 1)) exp = self.C[0:, 0:2] # self.assertEquals(exp.name(), "C[0:,0:2]") self.assertEquals(exp.size, (3, 2)) exp = self.C[0::2, 0::2] # self.assertEquals(exp.name(), "C[0::2,0::2]") self.assertEquals(exp.size, (2, 1)) exp = self.C[:3, :1:2] # self.assertEquals(exp.name(), "C[0:3,0]") self.assertEquals(exp.size, (3, 1)) exp = self.C[0:, 0] # self.assertEquals(exp.name(), "C[0:,0]") self.assertEquals(exp.size, (3, 1)) c = Constant([[1, -2], [0, 4]]) exp = c[1, 1] self.assertEqual(exp.curvature, u.Curvature.CONSTANT_KEY) self.assertEqual(exp.sign, u.Sign.POSITIVE_KEY) assert exp.is_positive() self.assertEqual(c[0, 1].sign, u.Sign.ZERO_KEY) assert c[0, 1].is_zero() self.assertEqual(c[1, 0].sign, u.Sign.NEGATIVE_KEY) assert c[1, 0].is_negative() self.assertEquals(exp.size, (1, 1)) self.assertEqual(exp.value, 4) c = Constant([[1, -2, 3], [0, 4, 5], [7, 8, 9]]) exp = c[0:3, 0:4:2] self.assertEqual(exp.curvature, u.Curvature.CONSTANT_KEY) assert exp.is_constant() self.assertEquals(exp.size, (3, 2)) self.assertEqual(exp[0, 1].value, 7) # Slice of transpose exp = self.C.T[0:2, 1] self.assertEquals(exp.size, (2, 1)) # Arithmetic expression indexing exp = (self.x + self.z)[1, 0] # self.assertEqual(exp.name(), "x[1,0] + z[1,0]") self.assertEqual(exp.curvature, u.Curvature.AFFINE_KEY) self.assertEqual(exp.sign, u.Sign.UNKNOWN_KEY) self.assertEquals(exp.size, (1, 1)) exp = (self.x + self.a)[1, 0] # self.assertEqual(exp.name(), "x[1,0] + a") self.assertEqual(exp.curvature, u.Curvature.AFFINE_KEY) self.assertEquals(exp.size, (1, 1)) exp = (self.x - self.z)[1, 0] # self.assertEqual(exp.name(), "x[1,0] - z[1,0]") self.assertEqual(exp.curvature, u.Curvature.AFFINE_KEY) self.assertEquals(exp.size, (1, 1)) exp = (self.x - self.a)[1, 0] # self.assertEqual(exp.name(), "x[1,0] - a") self.assertEqual(exp.curvature, u.Curvature.AFFINE_KEY) self.assertEquals(exp.size, (1, 1)) exp = (-self.x)[1, 0] # self.assertEqual(exp.name(), "-x[1,0]") self.assertEqual(exp.curvature, u.Curvature.AFFINE_KEY) self.assertEquals(exp.size, (1, 1)) c = Constant([[1, 2], [3, 4]]) exp = (c * self.x)[1, 0] # self.assertEqual(exp.name(), "[[2], [4]] * x[0:,0]") self.assertEqual(exp.curvature, u.Curvature.AFFINE_KEY) self.assertEquals(exp.size, (1, 1)) c = Constant([[1, 2], [3, 4]]) exp = (c * self.a)[1, 0] # self.assertEqual(exp.name(), "2 * a") self.assertEqual(exp.curvature, u.Curvature.AFFINE_KEY) self.assertEquals(exp.size, (1, 1))
def test_constants(self): c = Constant(2) self.assertEqual(c.name(), str(2)) c = Constant(2) self.assertEqual(c.value, 2) self.assertEqual(c.size, (1, 1)) self.assertEqual(c.curvature, u.Curvature.CONSTANT_KEY) self.assertEqual(c.sign, u.Sign.POSITIVE_KEY) self.assertEqual(Constant(-2).sign, u.Sign.NEGATIVE_KEY) self.assertEqual(Constant(0).sign, u.Sign.ZERO_KEY) self.assertEqual(c.canonical_form[0].size, (1, 1)) self.assertEqual(c.canonical_form[1], []) coeffs = c.coefficients() self.assertEqual(coeffs.keys(), [s.CONSTANT]) self.assertEqual(coeffs[s.CONSTANT], [2]) # Test the sign. c = Constant([[2], [2]]) self.assertEqual(c.size, (1, 2)) self.assertEqual(c._dcp_attr.sign.neg_mat.shape, (1, 2)) # Test sign of a complex expression. c = Constant([1, 2]) A = Constant([[1, 1], [1, 1]]) exp = c.T * A * c self.assertEqual(exp.sign, u.Sign.POSITIVE_KEY) self.assertEqual((c.T * c).sign, u.Sign.POSITIVE_KEY) exp = c.T.T self.assertEqual(exp._dcp_attr.sign.pos_mat.shape, (2, 1)) exp = c.T * self.A self.assertEqual(exp._dcp_attr.sign.pos_mat.shape, (1, 2))
def test_index_expression(self): # Tuple of integers as key. exp = self.x[1] # self.assertEqual(exp.name(), "x[1,0]") self.assertEqual(exp.curvature, s.AFFINE) assert exp.is_affine() self.assertEqual(exp.shape, tuple()) # coeff = exp.canonical_form[0].coefficients()[self.x][0] # self.assertEqual(coeff[0,1], 1) self.assertEqual(exp.value, None) exp = self.x[1].T # self.assertEqual(exp.name(), "x[1,0]") self.assertEqual(exp.curvature, s.AFFINE) self.assertEqual(exp.shape, tuple()) with self.assertRaises(Exception) as cm: (self.x[2, 0]) self.assertEqual(str(cm.exception), "Too many indices for expression.") with self.assertRaises(Exception) as cm: (self.x[2]) self.assertEqual(str(cm.exception), "Index 2 is out of bounds for axis 0 with size 2.") # Slicing exp = self.C[0:2, 1] # self.assertEqual(exp.name(), "C[0:2,1]") self.assertEqual(exp.shape, (2, )) exp = self.C[0:, 0:2] # self.assertEqual(exp.name(), "C[0:,0:2]") self.assertEqual(exp.shape, (3, 2)) exp = self.C[0::2, 0::2] # self.assertEqual(exp.name(), "C[0::2,0::2]") self.assertEqual(exp.shape, (2, 1)) exp = self.C[:3, :1:2] # self.assertEqual(exp.name(), "C[0:3,0]") self.assertEqual(exp.shape, (3, 1)) exp = self.C[0:, 0] # self.assertEqual(exp.name(), "C[0:,0]") self.assertEqual(exp.shape, (3, )) c = Constant([[1, -2], [0, 4]]) exp = c[1, 1] self.assertEqual(exp.curvature, s.CONSTANT) self.assertEqual(exp.sign, s.UNKNOWN) self.assertEqual(c[0, 1].sign, s.UNKNOWN) self.assertEqual(c[1, 0].sign, s.UNKNOWN) self.assertEqual(exp.shape, tuple()) self.assertEqual(exp.value, 4) c = Constant([[1, -2, 3], [0, 4, 5], [7, 8, 9]]) exp = c[0:3, 0:4:2] self.assertEqual(exp.curvature, s.CONSTANT) assert exp.is_constant() self.assertEqual(exp.shape, (3, 2)) self.assertEqual(exp[0, 1].value, 7) # Slice of transpose exp = self.C.T[0:2, 1:2] self.assertEqual(exp.shape, (2, 1)) # Arithmetic expression indexing exp = (self.x + self.z)[1] # self.assertEqual(exp.name(), "x[1,0] + z[1,0]") self.assertEqual(exp.curvature, s.AFFINE) self.assertEqual(exp.sign, s.UNKNOWN) self.assertEqual(exp.shape, tuple()) exp = (self.x + self.a)[1:2] # self.assertEqual(exp.name(), "x[1,0] + a") self.assertEqual(exp.curvature, s.AFFINE) self.assertEqual(exp.shape, (1, )) exp = (self.x - self.z)[1:2] # self.assertEqual(exp.name(), "x[1,0] - z[1,0]") self.assertEqual(exp.curvature, s.AFFINE) self.assertEqual(exp.shape, (1, )) exp = (self.x - self.a)[1] # self.assertEqual(exp.name(), "x[1,0] - a") self.assertEqual(exp.curvature, s.AFFINE) self.assertEqual(exp.shape, tuple()) exp = (-self.x)[1] # self.assertEqual(exp.name(), "-x[1,0]") self.assertEqual(exp.curvature, s.AFFINE) self.assertEqual(exp.shape, tuple()) c = Constant([[1, 2], [3, 4]]) exp = (c * self.x)[1] # self.assertEqual(exp.name(), "[[2], [4]] * x[0:,0]") self.assertEqual(exp.curvature, s.AFFINE) self.assertEqual(exp.shape, tuple()) c = Constant([[1, 2], [3, 4]]) exp = (c * self.a)[1, 0:1] # self.assertEqual(exp.name(), "2 * a") self.assertEqual(exp.curvature, s.AFFINE) self.assertEqual(exp.shape, (1, ))
def test_constants(self): c = Constant(2) self.assertEqual(c.name(), str(2)) c = Constant(2) self.assertEqual(c.value, 2) self.assertEqual(c.size, (1, 1)) self.assertEqual(c.curvature, u.Curvature.CONSTANT_KEY) self.assertEqual(c.sign, u.Sign.POSITIVE_KEY) self.assertEqual(Constant(-2).sign, u.Sign.NEGATIVE_KEY) self.assertEqual(Constant(0).sign, u.Sign.ZERO_KEY) self.assertEqual(c.canonical_form[0].size, (1, 1)) self.assertEqual(c.canonical_form[1], []) # coeffs = c.coefficients() # self.assertEqual(coeffs.keys(), [s.CONSTANT]) # self.assertEqual(coeffs[s.CONSTANT], [2]) # Test the sign. c = Constant([[2], [2]]) self.assertEqual(c.size, (1, 2)) self.assertEqual(c.sign, u.Sign.POSITIVE_KEY) self.assertEqual((-c).sign, u.Sign.NEGATIVE_KEY) self.assertEqual((0 * c).sign, u.Sign.ZERO_KEY) c = Constant([[2], [-2]]) self.assertEqual(c.sign, u.Sign.UNKNOWN_KEY) # Test sign of a complex expression. c = Constant([1, 2]) A = Constant([[1, 1], [1, 1]]) exp = c.T * A * c self.assertEqual(exp.sign, u.Sign.POSITIVE_KEY) self.assertEqual((c.T * c).sign, u.Sign.POSITIVE_KEY) exp = c.T.T self.assertEqual(exp.sign, u.Sign.POSITIVE_KEY) exp = c.T * self.A self.assertEqual(exp.sign, u.Sign.UNKNOWN_KEY) # Test repr. self.assertEqual(repr(c), "Constant(CONSTANT, POSITIVE, (2, 1))")