Beispiel #1
0
    def graph_implementation(arg_objs, size, data=None):
        """Reduces the atom to an affine expression and list of constraints.

        Parameters
        ----------
        arg_objs : list
            LinExpr for each argument.
        size : tuple
            The size of the resulting expression.
        data :
            Additional data required by the atom.

        Returns
        -------
        tuple
            (LinOp for objective, list of constraints)
        """
        X = arg_objs[0]  # n by m matrix.
        P = arg_objs[1]  # n by n matrix.
        n, m = X.size
        # Create a matrix with Schur complement T - X.T*P^-1*X.
        M = lu.create_var((n + m, n + m))
        T = lu.create_var((m, m))
        constraints = []
        # Fix M using the fact that P must be affine by the DCP rules.
        # M[0:n, 0:n] == P.
        index.block_eq(M, P, constraints, 0, n, 0, n)
        # M[0:n, n:n+m] == X
        index.block_eq(M, X, constraints, 0, n, n, n + m)
        # M[n:n+m, n:n+m] == T
        index.block_eq(M, T, constraints, n, n + m, n, n + m)
        # Add SDP constraint.
        return (lu.trace(T), constraints + [SDP(M)])
Beispiel #2
0
    def graph_implementation(arg_objs, size, data=None):
        """Reduces the atom to an affine expression and list of constraints.

        Parameters
        ----------
        arg_objs : list
            LinExpr for each argument.
        size : tuple
            The size of the resulting expression.
        data :
            Additional data required by the atom.

        Returns
        -------
        tuple
            (LinOp for objective, list of constraints)
        """
        x = arg_objs[0]
        P = arg_objs[1]  # n by n matrix.
        n, _ = P.size
        # Create a matrix with Schur complement t - x.T*P^-1*x.
        M = lu.create_var((n + 1, n + 1))
        t = lu.create_var((1, 1))
        constraints = []
        # Fix M using the fact that P must be affine by the DCP rules.
        # M[0:n, 0:n] == P.
        index.block_eq(M, P, constraints, 0, n, 0, n)
        # M[0:n, n:n+1] == x
        index.block_eq(M, x, constraints, 0, n, n, n + 1)
        # M[n:n+1, n:n+1] == t
        index.block_eq(M, t, constraints, n, n + 1, n, n + 1)
        # Add SDP constraint.
        return (t, constraints + [SDP(M)])
Beispiel #3
0
    def graph_implementation(arg_objs, size, data=None):
        """Reduces the atom to an affine expression and list of constraints.

        Parameters
        ----------
        arg_objs : list
            LinExpr for each argument.
        size : tuple
            The size of the resulting expression.
        data :
            Additional data required by the atom.

        Returns
        -------
        tuple
            (LinOp for objective, list of constraints)
        """
        axis = data[0]
        if axis is None:
            t = lu.create_var((1, 1))
            promoted_t = lu.promote(t, arg_objs[0].size)
        elif axis == 0:
            t = lu.create_var((1, arg_objs[0].size[1]))
            const_size = (arg_objs[0].size[0], 1)
            ones = lu.create_const(np.ones(const_size), const_size)
            promoted_t = lu.mul_expr(ones, t, arg_objs[0].size)
        else:  # axis == 1
            t = lu.create_var((arg_objs[0].size[0], 1))
            const_size = (1, arg_objs[0].size[1])
            ones = lu.create_const(np.ones(const_size), const_size)
            promoted_t = lu.rmul_expr(t, ones, arg_objs[0].size)

        constraints = [lu.create_leq(arg_objs[0], promoted_t)]
        return (t, constraints)
Beispiel #4
0
    def graph_implementation(arg_objs, size, data=None):
        """Reduces the atom to an affine expression and list of constraints.

        Parameters
        ----------
        arg_objs : list
            LinExpr for each argument.
        size : tuple
            The size of the resulting expression.
        data :
            Additional data required by the atom.

        Returns
        -------
        tuple
            (LinOp for objective, list of constraints)
        """
        # min sum_entries(t) + kq
        # s.t. x <= t + q
        #      0 <= t
        x = arg_objs[0]
        k = lu.create_const(data[0], (1, 1))
        q = lu.create_var((1, 1))
        t = lu.create_var(x.size)
        sum_t, constr = sum_entries.graph_implementation([t], (1, 1))
        obj = lu.sum_expr([sum_t, lu.mul_expr(k, q, (1, 1))])
        prom_q = lu.promote(q, x.size)
        constr.append(lu.create_leq(x, lu.sum_expr([t, prom_q])))
        constr.append(lu.create_geq(t))
        return (obj, constr)
Beispiel #5
0
    def graph_implementation(arg_objs, size, data=None):
        """Reduces the atom to an affine expression and list of constraints.

        Parameters
        ----------
        arg_objs : list
            LinExpr for each argument.
        size : tuple
            The size of the resulting expression.
        data :
            Additional data required by the atom.

        Returns
        -------
        tuple
            (LinOp for objective, list of constraints)
        """
        # min sum_entries(t) + kq
        # s.t. x <= t + q
        #      0 <= t
        x = arg_objs[0]
        k = lu.create_const(data[0], (1, 1))
        q = lu.create_var((1, 1))
        t = lu.create_var(x.size)
        sum_t, constr = sum_entries.graph_implementation([t], (1, 1))
        obj = lu.sum_expr([sum_t, lu.mul_expr(k, q, (1, 1))])
        prom_q = lu.promote(q, x.size)
        constr.append( lu.create_leq(x, lu.sum_expr([t, prom_q])) )
        constr.append( lu.create_geq(t) )
        return (obj, constr)
Beispiel #6
0
    def graph_implementation(arg_objs, size, data=None):
        """Reduces the atom to an affine expression and list of constraints.

        Parameters
        ----------
        arg_objs : list
            LinExpr for each argument.
        size : tuple
            The size of the resulting expression.
        data :
            Additional data required by the atom.

        Returns
        -------
        tuple
            (LinOp for objective, list of constraints)
        """
        x = arg_objs[0]
        w = lu.create_var(size)
        v = lu.create_var(size)
        two = lu.create_const(2, (1, 1))
        # w**2 + 2*v
        obj, constraints = square.graph_implementation([w], size)
        obj = lu.sum_expr([obj, lu.mul_expr(two, v, size)])
        # x <= w + v
        constraints.append(lu.create_leq(x, lu.sum_expr([w, v])))
        # v >= 0
        constraints.append(lu.create_geq(v))
        return (obj, constraints)
Beispiel #7
0
    def graph_implementation(arg_objs, size, data=None):
        """Reduces the atom to an affine expression and list of constraints.

        Parameters
        ----------
        arg_objs : list
            LinExpr for each argument.
        size : tuple
            The size of the resulting expression.
        data :
            Additional data required by the atom.

        Returns
        -------
        tuple
            (LinOp for objective, list of constraints)
        """
        x = arg_objs[0]
        w = lu.create_var(size)
        v = lu.create_var(size)
        two = lu.create_const(2, (1, 1))
        # w**2 + 2*v
        obj, constraints = square.graph_implementation([w], size)
        obj = lu.sum_expr([obj, lu.mul_expr(two, v, size)])
        # x <= w + v
        constraints.append(lu.create_leq(x, lu.sum_expr([w, v])))
        # v >= 0
        constraints.append(lu.create_geq(v))
        return (obj, constraints)
Beispiel #8
0
    def graph_implementation(arg_objs, size, data=None):
        """Reduces the atom to an affine expression and list of constraints.

        Parameters
        ----------
        arg_objs : list
            LinExpr for each argument.
        size : tuple
            The size of the resulting expression.
        data :
            Additional data required by the atom.

        Returns
        -------
        tuple
            (LinOp for objective, list of constraints)
        """
        A = arg_objs[0]  # n by m matrix.
        n, m = A.size
        # Create a matrix with Schur complement I*t - (1/t)*A.T*A.
        X = lu.create_var((n + m, n + m))
        t = lu.create_var((1, 1))
        constraints = []
        # Fix X using the fact that A must be affine by the DCP rules.
        # X[0:n, 0:n] == I_n*t
        prom_t = lu.promote(t, (n, 1))
        index.block_eq(X, lu.diag_vec(prom_t), constraints, 0, n, 0, n)
        # X[0:n, n:n+m] == A
        index.block_eq(X, A, constraints, 0, n, n, n + m)
        # X[n:n+m, n:n+m] == I_m*t
        prom_t = lu.promote(t, (m, 1))
        # prom_t = lu.promote(lu.create_const(1, (1,1)), (m, 1))
        index.block_eq(X, lu.diag_vec(prom_t), constraints, n, n + m, n, n + m)
        # Add SDP constraint.
        return (t, constraints + [SDP(X)])
Beispiel #9
0
 def test_add_expr(self):
     """Test adding lin expr.
     """
     shape = (5, 4)
     x = create_var(shape)
     y = create_var(shape)
     # Expanding dict.
     add_expr = sum_expr([x, y])
     self.assertEqual(add_expr.shape, shape)
     assert len(add_expr.args) == 2
Beispiel #10
0
 def test_get_vars(self):
     """Test getting vars from an expression.
     """
     shape = (5, 4)
     x = create_var(shape)
     y = create_var(shape)
     A = create_const(np.ones(shape), shape)
     # Expanding dict.
     add_expr = sum_expr([x, y, A])
     vars_ = get_expr_vars(add_expr)
     ref = [(x.data, shape), (y.data, shape)]
     self.assertCountEqual(vars_, ref)
Beispiel #11
0
 def test_leq_constr(self):
     """Test creating a less than or equal constraint.
     """
     shape = (5, 5)
     x = create_var(shape)
     y = create_var(shape)
     lh_expr = sum_expr([x, y])
     value = np.ones(shape)
     rh_expr = create_const(value, shape)
     constr = create_leq(lh_expr, rh_expr)
     self.assertEqual(constr.shape, shape)
     vars_ = get_expr_vars(constr.expr)
     ref = [(x.data, shape), (y.data, shape)]
     self.assertCountEqual(vars_, ref)
Beispiel #12
0
 def graph_implementation(arg_objs, size, data=None):
     # min 1-sqrt(2z-z^2)
     # s.t. x>=0, z<=1, z = x+s, s<=0
     x = arg_objs[0]
     z = lu.create_var(size)
     s = lu.create_var(size)
     zeros = lu.create_const(np.mat(np.zeros(size)),size)
     ones = lu.create_const(np.mat(np.ones(size)),size)
     z2, constr_square = power.graph_implementation([z],size, (2, (Fraction(1,2), Fraction(1,2))))
     two_z = lu.sum_expr([z,z])
     sub = lu.sub_expr(two_z, z2)
     sq, constr_sqrt = power.graph_implementation([sub],size, (Fraction(1,2), (Fraction(1,2), Fraction(1,2))))
     obj = lu.sub_expr(ones, sq)
     constr = [lu.create_eq(z, lu.sum_expr([x,s]))]+[lu.create_leq(zeros,x)]+[lu.create_leq(z, ones)]+[lu.create_leq(s,zeros)]+constr_square+constr_sqrt
     return (obj, constr)
Beispiel #13
0
    def graph_implementation(arg_objs, size, data=None):
        """Reduces the atom to an affine expression and list of constraints.

        Parameters
        ----------
        arg_objs : list
            LinExpr for each argument.
        size : tuple
            The size of the resulting expression.
        data :
            Additional data required by the atom.

        Returns
        -------
        tuple
            (LinOp for objective, list of constraints)
        """
        # Promote scalars.
        for idx, arg in enumerate(arg_objs):
            if arg.size != size:
                arg_objs[idx] = lu.promote(arg, size)
        x = arg_objs[0]
        y = arg_objs[1]
        v = lu.create_var(x.size)
        two = lu.create_const(2, (1, 1))
        # SOC(x + y, [y - x, 2*v])
        constraints = [
            SOC_Elemwise(lu.sum_expr([x, y]),
                         [lu.sub_expr(y, x),
                          lu.mul_expr(two, v, v.size)])
        ]
        # 0 <= x, 0 <= y
        constraints += [lu.create_geq(x), lu.create_geq(y)]
        return (v, constraints)
Beispiel #14
0
    def graph_implementation(arg_objs, size, data=None):
        """Reduces the atom to an affine expression and list of constraints.

        Parameters
        ----------
        arg_objs : list
            LinExpr for each argument.
        size : tuple
            The size of the resulting expression.
        data :
            Additional data required by the atom.

        Returns
        -------
        tuple
            (LinOp for objective, list of constraints)
        """
        A = arg_objs[0]
        n, _ = A.size
        # Requires that A is symmetric.
        obj, constraints = transpose.graph_implementation([A], (n, n))
        # A == A.T
        constraints.append(lu.create_eq(A, obj))
        # SDP constraint.
        t = lu.create_var((1, 1))
        prom_t = lu.promote(t, (n, 1))
        # I*t - A
        expr = lu.sub_expr(A, lu.diag_vec(prom_t))
        return (t, [SDP(expr)] + constraints)
Beispiel #15
0
    def graph_implementation(arg_objs, size, data=None):
        """Reduces the atom to an affine expression and list of constraints.

        Parameters
        ----------
        arg_objs : list
            LinExpr for each argument.
        size : tuple
            The size of the resulting expression.
        data :
            Additional data required by the atom.

        Returns
        -------
        tuple
            (LinOp for objective, list of constraints)
        """
        x = arg_objs[0]
        t = lu.create_var((1, 1))
        # sum(exp(x - t))
        prom_t = lu.promote(t, x.size)
        expr = lu.sub_expr(x, prom_t)
        obj, constraints = exp.graph_implementation([expr], x.size)
        obj, constr = sum_entries.graph_implementation([obj], (1, 1))
        # obj <= 1
        one = lu.create_const(1, (1, 1))
        constraints += constr + [lu.create_leq(obj, one)]
        return (t, constraints)
Beispiel #16
0
    def graph_implementation(self, arg_objs, shape, data=None):
        """Cumulative sum via difference matrix.

        Parameters
        ----------
        arg_objs : list
            LinExpr for each argument.
        shape : tuple
            The shape of the resulting expression.
        data :
            Additional data required by the atom.

        Returns
        -------
        tuple
            (LinOp for objective, list of constraints)
        """
        # Implicit O(n) definition:
        # X = Y[1:,:] - Y[:-1, :]
        Y = lu.create_var(shape)
        axis = data[0]
        dim = shape[axis]
        diff_mat = get_diff_mat(dim, axis)
        diff_mat = lu.create_const(diff_mat, (dim, dim), sparse=True)
        if axis == 0:
            diff = lu.mul_expr(diff_mat, Y)
        else:
            diff = lu.rmul_expr(Y, diff_mat)
        return (Y, [lu.create_eq(arg_objs[0], diff)])
Beispiel #17
0
    def graph_implementation(arg_objs, size, data=None):
        """Reduces the atom to an affine expression and list of constraints.

        Parameters
        ----------
        arg_objs : list
            LinExpr for each argument.
        size : tuple
            The size of the resulting expression.
        data :
            Additional data required by the atom.

        Returns
        -------
        tuple
            (LinOp for objective, list of constraints)
        """
        x = arg_objs[0]
        y = arg_objs[1]
        t = lu.create_var((1, 1))
        constraints = [ExpCone(t, x, y),
                       lu.create_geq(y)] # 0 <= y
        # -t - x + y
        obj = lu.sub_expr(y, lu.sum_expr([x, t]))
        return (obj, constraints)
Beispiel #18
0
    def graph_implementation(arg_objs, size, data=None):
        """Reduces the atom to an affine expression and list of constraints.

        Parameters
        ----------
        arg_objs : list
            LinExpr for each argument.
        size : tuple
            The size of the resulting expression.
        data :
            Additional data required by the atom.

        Returns
        -------
        tuple
            (LinOp for objective, list of constraints)
        """
        A = arg_objs[0]
        rows, cols = A.size
        # Create the equivalent problem:
        #   minimize (trace(U) + trace(V))/2
        #   subject to:
        #            [U A; A.T V] is positive semidefinite
        X = lu.create_var((rows+cols, rows+cols))
        constraints = []
        # Fix X using the fact that A must be affine by the DCP rules.
        # X[0:rows,rows:rows+cols] == A
        index.block_eq(X, A, constraints,
                       0, rows, rows, rows+cols)
        half = lu.create_const(0.5, (1, 1))
        trace = lu.mul_expr(half, lu.trace(X), (1, 1))
        # Add SDP constraint.
        return (trace, [SDP(X)] + constraints)
Beispiel #19
0
    def graph_implementation(arg_objs, size, data=None):
        """Reduces the atom to an affine expression and list of constraints.

        Parameters
        ----------
        arg_objs : list
            LinExpr for each argument.
        size : tuple
            The size of the resulting expression.
        data :
            Additional data required by the atom.

        Returns
        -------
        tuple
            (LinOp for objective, list of constraints)
        """
        A = arg_objs[0]
        n, _ = A.size
        # Requires that A is symmetric.
        obj, constraints = transpose.graph_implementation([A], (n, n))
        # A == A.T
        constraints.append(lu.create_eq(A, obj))
        # SDP constraint.
        t = lu.create_var((1, 1))
        prom_t = lu.promote(t, (n, 1))
        # I*t - A
        expr = lu.sub_expr(A, lu.diag_vec(prom_t))
        return (t, [SDP(expr)] + constraints)
Beispiel #20
0
    def graph_implementation(arg_objs, size, data=None):
        """Reduces the atom to an affine expression and list of constraints.

        Parameters
        ----------
        arg_objs : list
            LinExpr for each argument.
        size : tuple
            The size of the resulting expression.
        data :
            Additional data required by the atom.

        Returns
        -------
        tuple
            (LinOp for objective, list of constraints)
        """
        w, w_dyad, tree = data
        t = lu.create_var((1, 1))

        if arg_objs[0].size[1] == 1:
            x_list = [
                index.get_index(arg_objs[0], [], i, 0) for i in range(len(w))
            ]
        if arg_objs[0].size[0] == 1:
            x_list = [
                index.get_index(arg_objs[0], [], 0, i) for i in range(len(w))
            ]

        # todo: catch cases where we have (0, 0, 1)?
        # todo: what about curvature case (should be affine) in trivial case of (0, 0 , 1),
        # should this behavior match with what we do in power?

        return t, gm_constrs(t, x_list, w)
Beispiel #21
0
    def graph_implementation(arg_objs, size, data=None):
        """Reduces the atom to an affine expression and list of constraints.

        Parameters
        ----------
        arg_objs : list
            LinExpr for each argument.
        size : tuple
            The size of the resulting expression.
        data :
            Additional data required by the atom.

        Returns
        -------
        tuple
            (LinOp for objective, list of constraints)
        """
        x = arg_objs[0]
        y = arg_objs[1]
        t = lu.create_var((1, 1))
        constraints = [ExpCone(t, x, y),
                       lu.create_geq(y)] # 0 <= y
        # -t - x + y
        obj = lu.sub_expr(y, lu.sum_expr([x, t]))
        return (obj, constraints)
Beispiel #22
0
    def graph_implementation(arg_objs, size, data=None):
        """Stack the expressions horizontally.

        Parameters
        ----------
        arg_objs : list
            LinExpr for each argument.
        size : tuple
            The size of the resulting expression.
        data :
            Additional data required by the atom.

        Returns
        -------
        tuple
            (LinOp for objective, list of constraints)
        """
        X = lu.create_var(size)
        constraints = []
        # Create an equality constraint for each arg.
        offset = 0
        for arg in arg_objs:
            index.block_eq(X, arg, constraints,
                           0, size[0],
                           offset, arg.size[1] + offset)
            offset += arg.size[1]
        return (X, constraints)
Beispiel #23
0
    def format(self, eq_constr, leq_constr, dims, solver):
        """Formats EXP constraints for the solver.

        Parameters
        ----------
        eq_constr : list
            A list of the equality constraints in the canonical problem.
        leq_constr : list
            A list of the inequality constraints in the canonical problem.
        dims : dict
            A dict with the dimensions of the conic constraints.
        solver : str
            The solver being called.
        """
        # Need x, y, z to be lone Variables.
        if solver == s.CVXOPT:
            constraints = []
            for i, var in enumerate(self.vars_):
                if not var.type is VARIABLE:
                    lone_var = lu.create_var(var.size)
                    constraints.append(lu.create_eq(lone_var, var))
                    self.vars_[i] = lone_var
            eq_constr += constraints
        # Converts to an inequality constraint.
        elif solver == s.SCS:
            leq_constr += format_elemwise([self.x, self.y, self.z])
        else:
            raise ValueError("Solver does not support exponential cone.")
        # Update dims.
        dims[s.EXP_DIM] += self.size[0]*self.size[1]
Beispiel #24
0
    def graph_implementation(arg_objs, size, data=None):
        """Stack the expressions vertically.

        Parameters
        ----------
        arg_objs : list
            LinExpr for each argument.
        size : tuple
            The size of the resulting expression.
        data :
            Additional data required by the atom.

        Returns
        -------
        tuple
            (LinOp for objective, list of constraints)
        """
        X = lu.create_var(size)
        constraints = []
        # Create an equality constraint for each arg.
        offset = 0
        for arg in arg_objs:
            index.block_eq(X, arg, constraints,
                           offset, arg.size[0] + offset,
                           0, size[1])
            offset += arg.size[0]
        return (X, constraints)
Beispiel #25
0
    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 CVXcanon for this.
        # Make a fake lin op tree for the function.
        fake_args = []
        var_offsets = {}
        offset = 0
        for idx, arg in enumerate(self.args):
            fake_args += [lu.create_var(arg.size, idx)]
            var_offsets[idx] = offset
            offset += arg.size[0] * arg.size[1]
        fake_expr, _ = self.graph_implementation(fake_args, self.size,
                                                 self.get_data())
        # Get the matrix representation of the function.
        V, I, J, _ = canonInterface.get_problem_matrix(
            [lu.create_eq(fake_expr)], var_offsets, None)
        shape = (offset, self.size[0] * self.size[1])
        stacked_grad = sp.coo_matrix((V, (J, I)), shape=shape).tocsc()
        # Break up into per argument matrices.
        grad_list = []
        start = 0
        for idx, arg in enumerate(self.args):
            stop = start + arg.size[0] * arg.size[1]
            grad_list += [stacked_grad[start:stop, :]]
            start = stop
        return grad_list
Beispiel #26
0
    def graph_implementation(arg_objs, size, data=None):
        """Reduces the atom to an affine expression and list of constraints.

        Parameters
        ----------
        arg_objs : list
            LinExpr for each argument.
        size : tuple
            The size of the resulting expression.
        data :
            Additional data required by the atom.

        Returns
        -------
        tuple
            (LinOp for objective, list of constraints)
        """
        t = lu.create_var(size)
        constraints = []
        for obj in arg_objs:
            # Promote obj.
            if obj.size != size:
                obj = lu.promote(obj, size)
            constraints.append(lu.create_leq(obj, t))
        return (t, constraints)
Beispiel #27
0
    def graph_implementation(arg_objs, size, data=None):
        """Cumulative sum via difference matrix.

        Parameters
        ----------
        arg_objs : list
            LinExpr for each argument.
        size : tuple
            The size of the resulting expression.
        data :
            Additional data required by the atom.

        Returns
        -------
        tuple
            (LinOp for objective, list of constraints)
        """
        # Implicit O(n) definition:
        # X = Y[:1,:] - Y[1:,:]
        Y = lu.create_var(size)
        axis = data[0]
        dim = size[axis]
        diff_mat = get_diff_mat(dim, axis)
        diff_mat = lu.create_const(diff_mat, (dim, dim), sparse=True)
        if axis == 0:
            diff = lu.mul_expr(diff_mat, Y, size)
        else:
            diff = lu.rmul_expr(Y, diff_mat, size)
        return (Y, [lu.create_eq(arg_objs[0], diff)])
Beispiel #28
0
    def __format(self, solver):
        """Internal version of format with cached results.

        Returns
        -------
        tuple
            (equality constraints, inequality constraints)
        """
        eq_constr = []
        leq_constr = []
        # Need x, y, z to be lone Variables.
        if solver == s.CVXOPT:
            constraints = []
            for i, var in enumerate(self.vars_):
                if not var.type is VARIABLE:
                    lone_var = lu.create_var(var.size)
                    constraints.append(lu.create_eq(lone_var, var))
                    self.vars_[i] = lone_var
            eq_constr += constraints
        # Converts to an inequality constraint.
        elif solver == s.SCS:
            leq_constr += format_elemwise([self.x, self.y, self.z])
        else:
            raise SolverError("Solver does not support exponential cone.")
        return (eq_constr, leq_constr)
Beispiel #29
0
    def graph_implementation(arg_objs, size, data=None):
        """Reduces the atom to an affine expression and list of constraints.

        Parameters
        ----------
        arg_objs : list
            LinExpr for each argument.
        size : tuple
            The size of the resulting expression.
        data :
            Additional data required by the atom.

        Returns
        -------
        tuple
            (LinOp for objective, list of constraints)
        """
        x = arg_objs[0]
        t = lu.create_var(size)

        # log(1 + exp(x)) <= t <=> exp(-t) + exp(x - t) <= 1
        obj0, constr0 = exp.graph_implementation([lu.neg_expr(t)], size)
        obj1, constr1 = exp.graph_implementation([lu.sub_expr(x, t)], size)
        lhs = lu.sum_expr([obj0, obj1])
        ones = lu.create_const(np.mat(np.ones(size)), size)
        constr = constr0 + constr1 + [lu.create_leq(lhs, ones)]

        return (t, constr)
Beispiel #30
0
    def graph_implementation(arg_objs, size, data=None):
        """Reduces the atom to an affine expression and list of constraints.

        Parameters
        ----------
        arg_objs : list
            LinExpr for each argument.
        size : tuple
            The size of the resulting expression.
        data :
            Additional data required by the atom.

        Returns
        -------
        tuple
            (LinOp for objective, list of constraints)
        """
        A = arg_objs[0]
        rows, cols = A.size
        # Create the equivalent problem:
        #   minimize (trace(U) + trace(V))/2
        #   subject to:
        #            [U A; A.T V] is positive semidefinite
        X = lu.create_var((rows + cols, rows + cols))
        constraints = []
        # Fix X using the fact that A must be affine by the DCP rules.
        # X[0:rows,rows:rows+cols] == A
        index.block_eq(X, A, constraints, 0, rows, rows, rows + cols)
        half = lu.create_const(0.5, (1, 1))
        trace = lu.mul_expr(half, lu.trace(X), (1, 1))
        # Add SDP constraint.
        return (trace, [SDP(X)] + constraints)
Beispiel #31
0
def qol_elemwise(arg_objs, size, data=None):
    """Reduces the atom to an affine expression and list of constraints.

    Parameters
    ----------
    arg_objs : list
        LinExpr for each argument.
    size : tuple
        The size of the resulting expression.
    data :
        Additional data required by the atom.

    Returns
    -------
    tuple
        (LinOp for objective, list of constraints)
    """
    x = arg_objs[0]
    y = arg_objs[1]
    t = lu.create_var(x.size)
    two = lu.create_const(2, (1, 1))
    constraints = [
        SOC_Elemwise(
            lu.sum_expr([y, t]),
            [lu.sub_expr(y, t), lu.mul_expr(two, x, x.size)]),
        lu.create_geq(y)
    ]
    return (t, constraints)
Beispiel #32
0
    def format(self, eq_constr, leq_constr, dims, solver):
        """Formats EXP constraints for the solver.

        Parameters
        ----------
        eq_constr : list
            A list of the equality constraints in the canonical problem.
        leq_constr : list
            A list of the inequality constraints in the canonical problem.
        dims : dict
            A dict with the dimensions of the conic constraints.
        solver : str
            The solver being called.
        """
        # Need x, y, z to be lone Variables.
        if solver == s.CVXOPT:
            constraints = []
            for i, var in enumerate(self.vars_):
                if not var.type is VARIABLE:
                    lone_var = lu.create_var(var.size)
                    constraints.append(lu.create_eq(lone_var, var))
                    self.vars_[i] = lone_var
            eq_constr += constraints
        # Converts to an inequality constraint.
        elif solver == s.SCS:
            leq_constr += format_elemwise([self.x, self.y, self.z])
        else:
            raise ValueError("Solver does not support exponential cone.")
        # Update dims.
        dims[s.EXP_DIM] += self.size[0] * self.size[1]
Beispiel #33
0
    def graph_implementation(arg_objs, size, data=None):
        """Convolve two vectors.

        Parameters
        ----------
        arg_objs : list
            LinExpr for each argument.
        size : tuple
            The size of the resulting expression.
        data :
            Additional data required by the atom.

        Returns
        -------
        tuple
            (LinOp for objective, list of constraints)
        """
        # Implicit O(n) definition:
        # X = Y[:1,:] - Y[1:,:]
        Y = lu.create_var(size)
        axis = data[0]
        dim = size[axis]
        diff_mat = get_diff_mat(dim, axis)
        diff_mat = lu.create_const(diff_mat, (dim, dim), sparse=True)
        if axis == 0:
            diff = lu.mul_expr(diff_mat, Y, size)
        else:
            diff = lu.rmul_expr(Y, diff_mat, size)
        return (Y, [lu.create_eq(arg_objs[0], diff)])
Beispiel #34
0
    def graph_implementation(arg_objs, size, data=None):
        """Reduces the atom to an affine expression and list of constraints.

        Parameters
        ----------
        arg_objs : list
            LinExpr for each argument.
        size : tuple
            The size of the resulting expression.
        data :
            Additional data required by the atom.

        Returns
        -------
        tuple
            (LinOp for objective, list of constraints)
        """
        x = arg_objs[0]
        t = lu.create_var((1, 1))
        promoted_t = lu.promote(t, x.size)
        constraints = [
            lu.create_geq(lu.sum_expr([x, promoted_t])),
            lu.create_leq(x, promoted_t)
        ]
        return (t, constraints)
Beispiel #35
0
    def graph_implementation(arg_objs, size, data=None):
        """Reduces the atom to an affine expression and list of constraints.

        Parameters
        ----------
        arg_objs : list
            LinExpr for each argument.
        size : tuple
            The size of the resulting expression.
        data :
            Additional data required by the atom.

        Returns
        -------
        tuple
            (LinOp for objective, list of constraints)
        """
        t = lu.create_var(size)
        constraints = []
        for obj in arg_objs:
            # Promote obj.
            if obj.size != size:
                obj = lu.promote(obj, size)
            constraints.append(lu.create_leq(obj, t))
        return (t, constraints)
Beispiel #36
0
    def graph_implementation(arg_objs, size, data=None):
        """Reduces the atom to an affine expression and list of constraints.

        Parameters
        ----------
        arg_objs : list
            LinExpr for each argument.
        size : tuple
            The size of the resulting expression.
        data :
            Additional data required by the atom.

        Returns
        -------
        tuple
            (LinOp for objective, list of constraints)
        """
        # TODO use log for n != 2.
        v = lu.create_var((1, 1))
        x = arg_objs[0]
        y = arg_objs[1]
        two = lu.create_const(2, (1, 1))
        # SOC(x + y, [y - x, 2*v])
        constraints = [
            SOC(lu.sum_expr([x, y]),
                [lu.sub_expr(y, x),
                 lu.mul_expr(two, v, (1, 1))])
        ]
        # 0 <= x, 0 <= y
        constraints += [lu.create_geq(x), lu.create_geq(y)]
        return (v, constraints)
Beispiel #37
0
def qol_elemwise(arg_objs, size, data=None):
    """Reduces the atom to an affine expression and list of constraints.

    Parameters
    ----------
    arg_objs : list
        LinExpr for each argument.
    size : tuple
        The size of the resulting expression.
    data :
        Additional data required by the atom.

    Returns
    -------
    tuple
        (LinOp for objective, list of constraints)
    """
    x = arg_objs[0]
    y = arg_objs[1]
    t = lu.create_var(x.size)
    two = lu.create_const(2, (1, 1))
    constraints = [SOC_Elemwise(lu.sum_expr([y, t]),
                                [lu.sub_expr(y, t),
                                 lu.mul_expr(two, x, x.size)]),
                   lu.create_geq(y)]
    return (t, constraints)
Beispiel #38
0
    def graph_implementation(arg_objs, size, data=None):
        """Reduces the atom to an affine expression and list of constraints.

        Parameters
        ----------
        arg_objs : list
            LinExpr for each argument.
        size : tuple
            The size of the resulting expression.
        data :
            Additional data required by the atom.

        Returns
        -------
        tuple
            (LinOp for objective, list of constraints)
        """
        w, w_dyad, tree = data
        t = lu.create_var((1, 1))

        if arg_objs[0].size[1] == 1:
            x_list = [index.get_index(arg_objs[0], [], i, 0) for i in range(len(w))]
        if arg_objs[0].size[0] == 1:
            x_list = [index.get_index(arg_objs[0], [], 0, i) for i in range(len(w))]

        #todo: catch cases where we have (0, 0, 1)?
        #todo: what about curvature case (should be affine) in trivial case of (0, 0 , 1), should this behavior match with what we do in power?

        return t, gm_constrs(t, x_list, w)
Beispiel #39
0
    def graph_implementation(arg_objs, size, data=None):
        """Reduces the atom to an affine expression and list of constraints.

        Parameters
        ----------
        arg_objs : list
            LinExpr for each argument.
        size : tuple
            The size of the resulting expression.
        data :
            Additional data required by the atom.

        Returns
        -------
        tuple
            (LinOp for objective, list of constraints)
        """
        x = arg_objs[0]
        y = arg_objs[1] # Known to be a scalar.
        v = lu.create_var((1, 1))
        two = lu.create_const(2, (1, 1))
        constraints = [SOC(lu.sum_expr([y, v]),
                           [lu.sub_expr(y, v),
                            lu.mul_expr(two, x, x.size)]),
                       lu.create_geq(y)]
        return (v, constraints)
Beispiel #40
0
    def graph_implementation(arg_objs, size, data=None):
        """Reduces the atom to an affine expression and list of constraints.

        Parameters
        ----------
        arg_objs : list
            LinExpr for each argument.
        size : tuple
            The size of the resulting expression.
        data :
            Additional data required by the atom.

        Returns
        -------
        tuple
            (LinOp for objective, list of constraints)
        """
        x = arg_objs[0]
        t = lu.create_var(size)

        # log(1 + exp(x)) <= t <=> exp(-t) + exp(x - t) <= 1
        obj0, constr0 = exp.graph_implementation([lu.neg_expr(t)], size)
        obj1, constr1 = exp.graph_implementation([lu.sub_expr(x, t)], size)
        lhs = lu.sum_expr([obj0, obj1])
        ones = lu.create_const(np.mat(np.ones(size)), size)
        constr = constr0 + constr1 + [lu.create_leq(lhs, ones)]

        return (t, constr)
Beispiel #41
0
    def graph_implementation(arg_objs, size, data=None):
        """Reduces the atom to an affine expression and list of constraints.

        Parameters
        ----------
        arg_objs : list
            LinExpr for each argument.
        size : tuple
            The size of the resulting expression.
        data :
            Additional data required by the atom.

        Returns
        -------
        tuple
            (LinOp for objective, list of constraints)
        """
        # Promote scalars.
        for idx, arg in enumerate(arg_objs):
            if arg.size != size:
                arg_objs[idx] = lu.promote(arg, size)
        x = arg_objs[0]
        y = arg_objs[1]
        v = lu.create_var(x.size)
        two = lu.create_const(2, (1, 1))
        # SOC(x + y, [y - x, 2*v])
        constraints = [
            SOC_Elemwise(lu.sum_expr([x, y]),
                         [lu.sub_expr(y, x),
                          lu.mul_expr(two, v, v.size)])
        ]
        # 0 <= x, 0 <= y
        constraints += [lu.create_geq(x), lu.create_geq(y)]
        return (v, constraints)
Beispiel #42
0
    def graph_implementation(arg_objs, size, data=None):
        """Reduces the atom to an affine expression and list of constraints.

        Parameters
        ----------
        arg_objs : list
            LinExpr for each argument.
        size : tuple
            The size of the resulting expression.
        data :
            Additional data required by the atom.

        Returns
        -------
        tuple
            (LinOp for objective, list of constraints)
        """
        x = arg_objs[0]
        y = arg_objs[1]  # Known to be a scalar.
        v = lu.create_var((1, 1))
        two = lu.create_const(2, (1, 1))
        constraints = [
            SOC(lu.sum_expr([y, v]),
                [lu.sub_expr(y, v),
                 lu.mul_expr(two, x, x.size)]),
            lu.create_geq(y)
        ]
        return (v, constraints)
Beispiel #43
0
    def graph_implementation(arg_objs, size, data=None):
        """Reduces the atom to an affine expression and list of constraints.

        Parameters
        ----------
        arg_objs : list
            LinExpr for each argument.
        size : tuple
            The size of the resulting expression.
        data :
            Additional data required by the atom.

        Returns
        -------
        tuple
            (LinOp for objective, list of constraints)
        """
        A = arg_objs[0]
        n, _ = A.size
        # SDP constraint.
        t = lu.create_var((1, 1))
        prom_t = lu.promote(t, (n, 1))
        # I*t - A
        expr = lu.sub_expr(lu.diag_vec(prom_t), A)
        return (t, [SDP(expr)])
Beispiel #44
0
    def graph_implementation(arg_objs, size, data=None):
        """Reduces the atom to an affine expression and list of constraints.

        Parameters
        ----------
        arg_objs : list
            LinExpr for each argument.
        size : tuple
            The size of the resulting expression.
        data :
            Additional data required by the atom.

        Returns
        -------
        tuple
            (LinOp for objective, list of constraints)
        """
        x = arg_objs[0]
        t = lu.create_var((1, 1))
        # sum(exp(x - t))
        prom_t = lu.promote(t, x.size)
        expr = lu.sub_expr(x, prom_t)
        obj, constraints = exp.graph_implementation([expr], x.size)
        obj, constr = sum_entries.graph_implementation([obj], (1, 1))
        # obj <= 1
        one = lu.create_const(1, (1, 1))
        constraints += constr + [lu.create_leq(obj, one)]
        return (t, constraints)
Beispiel #45
0
 def __init__(self, lin_op):
     self.lin_op = lin_op
     # Create a new nonconvex variable unless the lin_op is a variable.
     if lin_op.type is lo.VARIABLE:
         self.noncvx_var = lin_op
     else:
         self.noncvx_var = lu.create_var(self.lin_op.size)
     super(BoolConstr, self).__init__()
Beispiel #46
0
    def canonicalize(self):
        """Returns the graph implementation of the object.

        Returns:
            A tuple of (affine expression, [constraints]).
        """
        obj = lu.create_var(self.size, self.id)
        return (obj, [])
Beispiel #47
0
 def test_variables(self):
     """Test creating a variable.
     """
     var = create_var((5, 4), var_id=1)
     self.assertEqual(var.shape, (5, 4))
     self.assertEqual(var.data, 1)
     self.assertEqual(len(var.args), 0)
     self.assertEqual(var.type, VARIABLE)
Beispiel #48
0
 def __init__(self, lin_op):
     self.lin_op = lin_op
     # Create a new nonconvex variable unless the lin_op is a variable.
     if lin_op.type is lo.VARIABLE:
         self.noncvx_var = lin_op
     else:
         self.noncvx_var = lu.create_var(self.lin_op.size)
     super(BoolConstr, self).__init__()
Beispiel #49
0
 def __CVXOPT_format(self):
     constraints = []
     for i, var in enumerate(self.vars_):
         if not var.type is VARIABLE:
             lone_var = lu.create_var(var.size)
             constraints.append(lu.create_eq(lone_var, var))
             self.vars_[i] = lone_var
     return (constraints, [])
Beispiel #50
0
    def canonicalize(self):
        """Returns the graph implementation of the object.

        Returns:
            A tuple of (affine expression, [constraints]).
        """
        obj = lu.create_var(self.size, self.id)
        return (obj, [])
Beispiel #51
0
 def canonicalize(self):
     """Variable must be semidefinite and symmetric.
     """
     upper_tri = lu.create_var((self.size[0], 1), self.id)
     fill_coeff = upper_tri_to_full(self.n)
     fill_coeff = lu.create_const(fill_coeff, (self.n*self.n, self.size[0]),
                                  sparse=True)
     full_mat = lu.mul_expr(fill_coeff, upper_tri, (self.n*self.n, 1))
     full_mat = lu.reshape(full_mat, (self.n, self.n))
     return (upper_tri, [SDP(full_mat, enforce_sym=False)])
Beispiel #52
0
    def graph_implementation(arg_objs, size, data=None):
        """Reduces the atom to an affine expression and list of constraints.

        Parameters
        ----------
        arg_objs : list
            LinExpr for each argument.
        size : tuple
            The size of the resulting expression.
        data :
            Additional data required by the atom.

        Returns
        -------
        tuple
            (LinOp for objective, list of constraints)
        """
        x = arg_objs[0]
        axis = data[0]
        t = lu.create_var(size)

        # sum(exp(x - t)) <= 1
        if axis is None:
            prom_t = lu.promote(t, x.size)
            expr = lu.sub_expr(x, prom_t)
            obj, constraints = exp.graph_implementation([expr], x.size)
            obj = lu.sum_entries(obj)

        elif axis == 0:
            prom_size = (x.size[0], 1)
            ones = lu.create_const(np.ones(prom_size), prom_size)
            prom_t = lu.mul_expr(ones, t, x.size)
            expr = lu.sub_expr(x, prom_t)
            obj, constraints = exp.graph_implementation([expr], x.size)

            const_size = (1, x.size[0])
            ones = lu.create_const(np.ones(const_size), const_size)
            obj = lu.mul_expr(ones, obj, size)

        else:  # axis == 1
            prom_size = (1, x.size[1])
            ones = lu.create_const(np.ones(prom_size), prom_size)
            prom_t = lu.rmul_expr(t, ones, x.size)
            expr = lu.sub_expr(x, prom_t)
            obj, constraints = exp.graph_implementation([expr], x.size)

            const_size = (x.size[1], 1)
            ones = lu.create_const(np.ones(const_size), const_size)
            obj = lu.rmul_expr(obj, ones, size)

        ones = lu.create_const(np.ones(size), size)
        constraints += [lu.create_leq(obj, ones)]

        return (t, constraints)
Beispiel #53
0
    def graph_implementation(arg_objs,size,data=None):
        x = arg_objs[0]
        beta,x0 = data[0],data[1]
        beta_val,x0_val = beta.value,x0.value

        if isinstance(beta,Parameter):
            beta = lu.create_param(beta,(1,1))
        else:
            beta = lu.create_const(beta.value,(1,1))
        if isinstance(x0,Parameter):
            x0 = lu.create_param(x0,(1,1))
        else:
            x0 = lu.create_const(x0.value,(1,1))

        xi,psi = lu.create_var(size),lu.create_var(size)
        one = lu.create_const(1,(1,1))
        one_over_beta = lu.create_const(1/beta_val,(1,1))
        k = np.exp(-beta_val*x0_val)
        k = lu.create_const(k,(1,1))

        # 1/beta * (1 - exp(-beta*(xi+x0)))
        xi_plus_x0 = lu.sum_expr([xi,x0])
        minus_beta_times_xi_plus_x0  = lu.neg_expr(lu.mul_expr(beta,xi_plus_x0,size))
        exp_xi,constr_exp = exp.graph_implementation([minus_beta_times_xi_plus_x0],size)
        minus_exp_minus_etc = lu.neg_expr(exp_xi)
        left_branch = lu.mul_expr(one_over_beta, lu.sum_expr([one,minus_exp_minus_etc]),size)

        # psi*exp(-beta*r0)
        right_branch = lu.mul_expr(k,psi,size)

        obj = lu.sum_expr([left_branch,right_branch])

        #x-x0 == xi + psi, xi >= 0, psi <= 0
        zero = lu.create_const(0,size)
        constraints = constr_exp
        prom_x0 = lu.promote(x0, size)
        constraints.append(lu.create_eq(x,lu.sum_expr([prom_x0,xi,psi])))
        constraints.append(lu.create_geq(xi,zero))
        constraints.append(lu.create_leq(psi,zero))

        return (obj, constraints)
Beispiel #54
0
    def graph_implementation(arg_objs, size, data=None):
        """Reduces the atom to an affine expression and list of constraints.

        Parameters
        ----------
        arg_objs : list
            LinExpr for each argument.
        size : tuple
            The size of the resulting expression.
        data :
            Additional data required by the atom.

        Returns
        -------
        tuple
            (LinOp for objective, list of constraints)
        """
        A = arg_objs[0] # m by n matrix.
        n, m = A.size
        # Create a matrix with Schur complement I*t - (1/t)*A.T*A.
        X = lu.create_var((n+m, n+m))
        t = lu.create_var((1, 1))
        I_n = lu.create_const(sp.eye(n), (n, n))
        I_m = lu.create_const(sp.eye(m), (m, m))
        # Expand A.T.
        obj, constraints = transpose.graph_implementation([A], (m, n))
        # Fix X using the fact that A must be affine by the DCP rules.
        # X[0:n, 0:n] == I_n*t
        index.block_eq(X, lu.mul_expr(I_n, t, (n, n)), constraints,
                       0, n, 0, n)
        # X[0:n, n:n+m] == A
        index.block_eq(X, A, constraints,
                       0, n, n, n+m)
        # X[n:n+m, 0:n] == obj
        index.block_eq(X, obj, constraints,
                       n, n+m, 0, n)
        # X[n:n+m, n:n+m] == I_m*t
        index.block_eq(X, lu.mul_expr(I_m, t, (m, m)), constraints,
                       n, n+m, n, n+m)
        # Add SDP constraint.
        return (t, constraints + [SDP(X)])
Beispiel #55
0
    def graph_implementation(arg_objs, size, data=None):
        """Reduces the atom to an affine expression and list of constraints.

        minimize n^2 + 2M|s|
        subject to s + n = x

        Parameters
        ----------
        arg_objs : list
            LinExpr for each argument.
        size : tuple
            The size of the resulting expression.
        data :
            Additional data required by the atom.

        Returns
        -------
        tuple
            (LinOp for objective, list of constraints)
        """
        M = data
        x = arg_objs[0]
        n = lu.create_var(size)
        s = lu.create_var(size)
        two = lu.create_const(2, (1, 1))
        if isinstance(M, Parameter):
            M = lu.create_param(M, (1, 1))
        else: # M is constant.
            M = lu.create_const(M.value, (1, 1))

        # n**2 + 2*M*|s|
        n2, constr_sq = square.graph_implementation([n], size)
        abs_s, constr_abs = abs.graph_implementation([s], size)
        M_abs_s = lu.mul_expr(M, abs_s, size)
        obj = lu.sum_expr([n2, lu.mul_expr(two, M_abs_s, size)])
        # x == s + n
        constraints = constr_sq + constr_abs
        constraints.append(lu.create_eq(x, lu.sum_expr([n, s])))
        return (obj, constraints)
Beispiel #56
0
    def graph_implementation(arg_objs, size, data=None):
        """Reduces the atom to an affine expression and list of constraints.

        Parameters
        ----------
        arg_objs : list
            LinExpr for each argument.
        size : tuple
            The size of the resulting expression.
        data :
            Additional data required by the atom.

        Returns
        -------
        tuple
            (LinOp for objective, list of constraints)
        """
        A = arg_objs[0] # n by m matrix.
        n, m = A.size
        # Create a matrix with Schur complement I*t - (1/t)*A.T*A.
        X = lu.create_var((n+m, n+m))
        t = lu.create_var((1, 1))
        constraints = []
        # Fix X using the fact that A must be affine by the DCP rules.
        # X[0:n, 0:n] == I_n*t
        prom_t = lu.promote(t, (n, 1))
        index.block_eq(X, lu.diag_vec(prom_t), constraints,
                       0, n, 0, n)
        # X[0:n, n:n+m] == A
        index.block_eq(X, A, constraints,
                       0, n, n, n+m)
        # X[n:n+m, n:n+m] == I_m*t
        prom_t = lu.promote(t, (m, 1))
        # prom_t = lu.promote(lu.create_const(1, (1,1)), (m, 1))
        index.block_eq(X, lu.diag_vec(prom_t), constraints,
                       n, n+m, n, n+m)
        # Add SDP constraint.
        return (t, constraints + [SDP(X)])
Beispiel #57
0
def gm_constrs(t, x_list, p):
    """ Form the internal CXVPY constraints to form the weighted geometric mean t <= x^p.

    t <= x[0]^p[0] * x[1]^p[1] * ... * x[n]^p[n]

    where x and t can either be scalar or matrix variables.

    Parameters
    ----------

    t : cvx.Variable
        The epigraph variable

    x_list : list of cvx.Variable objects
        The vector of input variables. Must be the same length as ``p``.

    p : list or tuple of ``int`` and ``Fraction`` objects
        The powers vector. powers must be nonnegative and sum to *exactly* 1.
        Must be the same length as ``x``.

    Returns
    -------
    constr : list
        list of constraints involving elements of x (and possibly t) to form the geometric mean.

    """
    assert is_weight(p)
    w = dyad_completion(p)

    tree = decompose(w)
    d = defaultdict(lambda: lu.create_var(t.size))
    d[w] = t

    if len(x_list) < len(w):
        x_list += [t]

    assert len(x_list) == len(w)

    for i, (p, v) in enumerate(zip(w, x_list)):
        if p > 0:
            tmp = [0]*len(w)
            tmp[i] = 1
            d[tuple(tmp)] = v

    constraints = []
    for elem, children in tree.items():
        if 1 not in elem:
            constraints += [gm(d[elem], d[children[0]], d[children[1]])]

    return constraints