示例#1
0
    def test_problem_absorb(self):
        """Test problem object with absorption.
        """
        X = Variable((4, 2))
        B = np.reshape(np.arange(8, dtype=np.float32), (4, 2), order='F')

        # Absorbing lin ops.
        prox_fns = sum_squares(-2 * X, b=B) + norm1(5 * mul_elemwise(B, X))
        prob = Problem(prox_fns)
        prob.set_absorb(True)
        prob.solve(solver="admm", eps_rel=1e-6, eps_abs=1e-6)

        cvx_X = cvx.Variable((4, 2))
        cost = cvx.sum_squares(-2 * cvx_X - B) + cvx.norm(
            5 * cvx.multiply(B, cvx_X), 1)
        cvx_prob = cvx.Problem(cvx.Minimize(cost))
        cvx_prob.solve(solver=cvx.SCS)
        self.assertItemsAlmostEqual(X.value, cvx_X.value, places=2)

        prob.set_absorb(False)
        prob.solve(solver="admm", eps_rel=1e-6, eps_abs=1e-6)
        self.assertItemsAlmostEqual(X.value, cvx_X.value, places=2)

        # Constant offsets.
        prox_fns = sum_squares(-2 * X - B) + norm1(5 * mul_elemwise(B, X))
        prob = Problem(prox_fns)
        prob.solve(solver="admm", eps_rel=1e-6, eps_abs=1e-6)
        self.assertItemsAlmostEqual(X.value, cvx_X.value, places=2)
示例#2
0
    def test_mul_elemwise(self):
        """Test mul_elemwise lin op.
        """
        # Forward.
        var = Variable((2, 5))
        W = np.arange(10)
        W = np.reshape(W, (2, 5))
        fn = mul_elemwise(W, var)
        x = W.copy()
        out = np.zeros(x.shape)
        fn.forward([x], [out])
        self.assertItemsAlmostEqual(out, W * W)

        # Adjoint.
        x = W.copy()
        out = np.zeros(x.shape)
        fn.adjoint([x], [out])
        self.assertItemsAlmostEqual(out, W * W)

        # Diagonal form.
        x = Variable(5)
        fn = mul_elemwise(np.arange(5) - 3, x)
        assert not fn.is_diag(freq=True)
        assert fn.is_diag(freq=False)
        self.assertItemsAlmostEqual(
            fn.get_diag(freq=False)[x],
            np.arange(5) - 3)
示例#3
0
    def test_mul_elemwise(self):
        """Test mul_elemwise lin op.
        """
        # Forward.
        var = Variable((2, 5))
        W = np.arange(10)
        W = np.reshape(W, (2, 5))
        fn = mul_elemwise(W, var)
        x = W.copy()
        out = np.zeros(x.shape)
        fn.forward([x], [out])
        self.assertItemsAlmostEqual(out, W * W)

        # Adjoint.
        x = W.copy()
        out = np.zeros(x.shape)
        fn.adjoint([x], [out])
        self.assertItemsAlmostEqual(out, W * W)

        # Diagonal form.
        x = Variable(5)
        fn = mul_elemwise(np.arange(5) - 3, x)
        assert not fn.is_diag(freq=True)
        assert fn.is_diag(freq=False)
        self.assertItemsAlmostEqual(fn.get_diag(freq=False)[x],
                                    np.arange(5) - 3)
示例#4
0
    def test_problem(self):
        """Test problem object.
        """
        X = Variable((4, 2))
        B = np.reshape(np.arange(8), (4, 2)) * 1.
        prox_fns = [norm1(X), sum_squares(X, b=B)]
        prob = Problem(prox_fns)
        # prob.partition(quad_funcs = [prox_fns[0], prox_fns[1]])
        prob.set_automatic_frequency_split(False)
        prob.set_absorb(False)
        prob.set_implementation(Impl['halide'])
        prob.set_solver('admm')
        prob.solve()

        true_X = norm1(X).prox(2, B.copy())
        self.assertItemsAlmostEqual(X.value, true_X, places=2)
        prob.solve(solver="pc")
        self.assertItemsAlmostEqual(X.value, true_X, places=2)
        prob.solve(solver="hqs", eps_rel=1e-6,
                   rho_0=1.0, rho_scale=np.sqrt(2.0) * 2.0, rho_max=2**16,
                   max_iters=20, max_inner_iters=500, verbose=False)
        self.assertItemsAlmostEqual(X.value, true_X, places=2)

        # CG
        prob = Problem(prox_fns)
        prob.set_lin_solver("cg")
        prob.solve(solver="admm")
        self.assertItemsAlmostEqual(X.value, true_X, places=2)
        prob.solve(solver="hqs", eps_rel=1e-6,
                   rho_0=1.0, rho_scale=np.sqrt(2.0) * 2.0, rho_max=2**16,
                   max_iters=20, max_inner_iters=500, verbose=False)
        self.assertItemsAlmostEqual(X.value, true_X, places=2)

        # Quad funcs.
        prob = Problem(prox_fns)
        prob.solve(solver="admm")
        self.assertItemsAlmostEqual(X.value, true_X, places=2)

        # Absorbing lin ops.
        prox_fns = [norm1(5 * mul_elemwise(B, X)), sum_squares(-2 * X, b=B)]
        prob = Problem(prox_fns)
        prob.set_absorb(True)
        prob.solve(solver="admm", eps_rel=1e-6, eps_abs=1e-6)

        cvx_X = cvx.Variable(4, 2)
        cost = cvx.sum_squares(-2 * cvx_X - B) + cvx.norm(5 * cvx.mul_elemwise(B, cvx_X), 1)
        cvx_prob = cvx.Problem(cvx.Minimize(cost))
        cvx_prob.solve(solver=cvx.SCS)
        self.assertItemsAlmostEqual(X.value, cvx_X.value, places=2)

        prob.set_absorb(False)
        prob.solve(solver="admm", eps_rel=1e-6, eps_abs=1e-6)
        self.assertItemsAlmostEqual(X.value, cvx_X.value, places=2)

        # Constant offsets.
        prox_fns = [norm1(5 * mul_elemwise(B, X)), sum_squares(-2 * X - B)]
        prob = Problem(prox_fns)
        prob.solve(solver="admm", eps_rel=1e-6, eps_abs=1e-6)
        self.assertItemsAlmostEqual(X.value, cvx_X.value, places=2)
示例#5
0
 def absorb_params(self):
     """Returns an equivalent sum_squares with alpha = 1.0,
        gamma = 0, and c = 0.
     """
     new_lin_op = mul_elemwise(self.weight, self.lin_op)
     new_b = mul_elemwise(self.weight, self.b).value
     return sum_squares(new_lin_op, alpha=self.alpha,
                        beta=self.beta, b=new_b, c=self.c, gamma=self.gamma).absorb_params()
示例#6
0
 def absorb_params(self):
     """Returns an equivalent sum_squares with alpha = 1.0,
        gamma = 0, and c = 0.
     """
     new_lin_op = mul_elemwise(self.weight, self.lin_op)
     new_b = mul_elemwise(self.weight, self.b).value
     return sum_squares(new_lin_op, alpha=self.alpha,
                        beta=self.beta, b=new_b, c=self.c, gamma=self.gamma).absorb_params()
示例#7
0
    def test_sum(self):
        # Forward.
        x = Variable((2, 3))
        y = Variable((2, 3))
        fn = sum([x, y])
        x_val = np.reshape(np.arange(6) * 1.0, x.shape)
        y_val = np.reshape(np.arange(6) * 1.0 - 5, x.shape)
        out = np.zeros(fn.shape)
        fn.forward([x_val, y_val], [out])
        self.assertItemsAlmostEqual(out, 2 * np.arange(6) - 5)

        # Adjoint.
        x_val = np.reshape(np.arange(6) * 1.0, x.shape)
        out = [np.zeros(fn.shape), np.zeros(fn.shape)]
        fn.adjoint([x_val], out)
        for arr in out:
            self.assertItemsAlmostEqual(arr, x_val)

        # Constant args.
        x = Variable((2, 3))
        y = Variable((2, 3))
        x_val = np.reshape(np.arange(6) * 1.0, x.shape)
        y_val = np.reshape(np.arange(6) * 1.0 - 5, x.shape)
        fn = sum([x_val, y_val])
        self.assertItemsAlmostEqual(fn.value, 2 * np.arange(6) - 5)

        # Diagonal form.
        x = Variable(5)
        term = mul_elemwise(np.arange(5) - 3, x)
        fn = sum([term, x])
        assert not fn.is_diag(freq=True)
        assert fn.is_diag(freq=False)
        self.assertItemsAlmostEqual(
            fn.get_diag(freq=False)[x],
            np.arange(5) - 3 + np.ones(5))
示例#8
0
    def test_sum(self):
        # Forward.
        x = Variable((2, 3))
        y = Variable((2, 3))
        fn = sum([x, y])
        x_val = np.reshape(np.arange(6) * 1.0, x.shape)
        y_val = np.reshape(np.arange(6) * 1.0 - 5, x.shape)
        out = np.zeros(fn.shape)
        fn.forward([x_val, y_val], [out])
        self.assertItemsAlmostEqual(out, 2 * np.arange(6) - 5)

        # Adjoint.
        x_val = np.reshape(np.arange(6) * 1.0, x.shape)
        out = [np.zeros(fn.shape), np.zeros(fn.shape)]
        fn.adjoint([x_val], out)
        for arr in out:
            self.assertItemsAlmostEqual(arr, x_val)

        # Constant args.
        x = Variable((2, 3))
        y = Variable((2, 3))
        x_val = np.reshape(np.arange(6) * 1.0, x.shape)
        y_val = np.reshape(np.arange(6) * 1.0 - 5, x.shape)
        fn = sum([x_val, y_val])
        self.assertItemsAlmostEqual(fn.value, 2 * np.arange(6) - 5)

        # Diagonal form.
        x = Variable(5)
        term = mul_elemwise(np.arange(5) - 3, x)
        fn = sum([term, x])
        assert not fn.is_diag(freq=True)
        assert fn.is_diag(freq=False)
        self.assertItemsAlmostEqual(fn.get_diag(freq=False)[x],
                                    np.arange(5) - 3 + np.ones(5))
示例#9
0
    def test_problem(self):
        """Test problem object.
        """
        X = Variable((4, 2))
        B = np.reshape(np.arange(8), (4, 2)) * 1.
        prox_fns = [norm1(X), sum_squares(X, b=B)]
        prob = Problem(prox_fns)
        # prob.partition(quad_funcs = [prox_fns[0], prox_fns[1]])
        prob.set_automatic_frequency_split(False)
        prob.set_absorb(False)
        prob.set_implementation(Impl['halide'])
        prob.set_solver('admm')
        prob.solve()

        true_X = norm1(X).prox(2, B.copy())
        self.assertItemsAlmostEqual(X.value, true_X, places=2)
        prob.solve(solver="pc")
        self.assertItemsAlmostEqual(X.value, true_X, places=2)
        prob.solve(solver="hqs",
                   eps_rel=1e-6,
                   rho_0=1.0,
                   rho_scale=np.sqrt(2.0) * 2.0,
                   rho_max=2**16,
                   max_iters=20,
                   max_inner_iters=500,
                   verbose=False)
        self.assertItemsAlmostEqual(X.value, true_X, places=2)

        # CG
        prob = Problem(prox_fns)
        prob.set_lin_solver("cg")
        prob.solve(solver="admm")
        self.assertItemsAlmostEqual(X.value, true_X, places=2)
        prob.solve(solver="hqs",
                   eps_rel=1e-6,
                   rho_0=1.0,
                   rho_scale=np.sqrt(2.0) * 2.0,
                   rho_max=2**16,
                   max_iters=20,
                   max_inner_iters=500,
                   verbose=False)
        self.assertItemsAlmostEqual(X.value, true_X, places=2)

        # Quad funcs.
        prob = Problem(prox_fns)
        prob.solve(solver="admm")
        self.assertItemsAlmostEqual(X.value, true_X, places=2)

        # Absorbing lin ops.
        prox_fns = [norm1(5 * mul_elemwise(B, X)), sum_squares(-2 * X, b=B)]
        prob = Problem(prox_fns)
        prob.set_absorb(True)
        prob.solve(solver="admm", eps_rel=1e-6, eps_abs=1e-6)

        cvx_X = cvx.Variable(4, 2)
        cost = cvx.sum_squares(-2 * cvx_X - B) + cvx.norm(
            5 * cvx.mul_elemwise(B, cvx_X), 1)
        cvx_prob = cvx.Problem(cvx.Minimize(cost))
        cvx_prob.solve(solver=cvx.SCS)
        self.assertItemsAlmostEqual(X.value, cvx_X.value, places=2)

        prob.set_absorb(False)
        prob.solve(solver="admm", eps_rel=1e-6, eps_abs=1e-6)
        self.assertItemsAlmostEqual(X.value, cvx_X.value, places=2)

        # Constant offsets.
        prox_fns = [norm1(5 * mul_elemwise(B, X)), sum_squares(-2 * X - B)]
        prob = Problem(prox_fns)
        prob.solve(solver="admm", eps_rel=1e-6, eps_abs=1e-6)
        self.assertItemsAlmostEqual(X.value, cvx_X.value, places=2)
示例#10
0
    def test_op_overloading(self):
        """Test operator overloading.
        """
        # Multiplying by a scalar.

        # Forward.
        var = Variable((2, 5))
        W = np.arange(10)
        W = np.reshape(W, (2, 5))
        fn = -2 * mul_elemwise(W, var)
        fn = CompGraph(fn)
        x = W.copy()
        out = np.zeros(x.shape)
        fn.forward(x.flatten(), out)
        self.assertItemsAlmostEqual(out, -2 * W * W)

        # Adjoint.
        x = W.copy()
        out = np.zeros(x.shape).flatten()
        fn.adjoint(x, out)
        self.assertItemsAlmostEqual(out, -2 * W * W)

        # Forward.
        var = Variable((2, 5))
        W = np.arange(10)
        W = np.reshape(W, (2, 5))
        fn = mul_elemwise(W, var) * 0.5
        fn = CompGraph(fn)
        x = W.copy()
        out = np.zeros(x.shape)
        fn.forward(x.flatten(), out)
        self.assertItemsAlmostEqual(out, W * W / 2.)

        # Adjoint.
        x = W.copy()
        out = np.zeros(x.shape).flatten()
        fn.adjoint(x, out)
        self.assertItemsAlmostEqual(out, W * W / 2.)

        # Dividing by a scalar.
        # Forward.
        var = Variable((2, 5))
        W = np.arange(10)
        W = np.reshape(W, (2, 5))
        fn = mul_elemwise(W, var) / 2
        fn = CompGraph(fn)
        x = W.copy()
        out = np.zeros(x.shape)
        fn.forward(x, out)
        self.assertItemsAlmostEqual(out, W * W / 2.)

        # Adding lin ops.
        # Forward.
        x = Variable((2, 5))
        W = np.arange(10)
        W = np.reshape(W, (2, 5))
        fn = mul_elemwise(W, x)
        fn = fn + x + x
        self.assertEqual(len(fn.input_nodes), 3)
        fn = CompGraph(fn)
        x = W.copy()
        out = np.zeros(fn.shape)
        fn.forward(x, out)
        self.assertItemsAlmostEqual(out, W * W + 2 * W)

        # Adjoint.
        x = W.copy()
        out = np.zeros(x.shape).flatten()
        fn.adjoint(x, out)
        self.assertItemsAlmostEqual(out, W * W + 2 * W)

        # Adding in a constant.
        # CompGraph should ignore the constant.
        x = Variable((2, 5))
        W = np.arange(10)
        W = np.reshape(W, (2, 5))
        fn = mul_elemwise(W, x)
        fn = fn + x + W
        self.assertEqual(len(fn.input_nodes), 3)
        fn = CompGraph(fn)
        x = W.copy()
        out = np.zeros(fn.shape)
        fn.forward(x, out)
        self.assertItemsAlmostEqual(out, W * W + W)

        # Subtracting lin ops.
        # Forward.
        x = Variable((2, 5))
        W = np.arange(10)
        W = np.reshape(W, (2, 5))
        fn = -mul_elemwise(W, x)
        fn = x + x - fn
        self.assertEqual(len(fn.input_nodes), 3)
        fn = CompGraph(fn)
        x = W.copy()
        out = np.zeros(fn.shape)
        fn.forward(x, out)
        self.assertItemsAlmostEqual(out, W * W + 2 * W)

        # Adjoint.
        x = W.copy()
        out = np.zeros(x.shape).flatten()
        fn.adjoint(x, out)
        self.assertItemsAlmostEqual(out, W * W + 2 * W)
示例#11
0
    def test_absorb_lin_op(self):
        """Test absorb lin op operator.
        """
        # norm1.
        tmp = Variable(10)
        v = np.arange(10) * 1.0 - 5.0

        fn = norm1(mul_elemwise(-v, tmp), alpha=5.)
        rho = 2
        new_prox = absorb_lin_op(fn)[0]
        x = new_prox.prox(rho, v.copy())
        self.assertItemsAlmostEqual(x, np.sign(v) * np.maximum(np.abs(v) - 5. *
                                                               np.abs(v) / rho, 0))

        fn = norm1(mul_elemwise(-v, mul_elemwise(2 * v, tmp)), alpha=5.)
        rho = 2
        new_prox = absorb_lin_op(fn)[0]
        x = new_prox.prox(rho, v.copy())
        self.assertItemsAlmostEqual(x, np.sign(v) * np.maximum(np.abs(v) - 5. *
                                                               np.abs(v) / rho, 0))
        new_prox = absorb_lin_op(new_prox)[0]
        x = new_prox.prox(rho, v.copy())
        new_v = 2 * v * v
        self.assertItemsAlmostEqual(x, np.sign(new_v) *
                                    np.maximum(np.abs(new_v) - 5. * np.abs(new_v) / rho, 0))

        # nonneg.
        tmp = Variable(10)
        v = np.arange(10) * 1.0 - 5.0

        fn = nonneg(mul_elemwise(-v, tmp), alpha=5.)
        rho = 2
        new_prox = absorb_lin_op(fn)[0]
        x = new_prox.prox(rho, v.copy())
        self.assertItemsAlmostEqual(x, fn.prox(rho, -np.abs(v)))

        # sum_squares.
        tmp = Variable(10)
        v = np.arange(10) * 1.0 - 5.0

        alpha = 5.
        val = np.arange(10)
        fn = sum_squares(mul_elemwise(-v, tmp), alpha=alpha, c=val)
        rho = 2
        new_prox = absorb_lin_op(fn)[0]
        x = new_prox.prox(rho, v.copy())

        cvx_x = cvx.Variable(10)
        prob = cvx.Problem(cvx.Minimize(cvx.sum_squares(cvx_x - v) * (rho / 2) +
                                        5 * cvx.sum_squares(cvx.mul_elemwise(-v,
                                                            cvx_x)) + (val * -v).T * cvx_x
                                        ))
        prob.solve()
        self.assertItemsAlmostEqual(x, cvx_x.value, places=3)

        # Test scale.
        tmp = Variable(10)
        v = np.arange(10) * 1.0 - 5.0

        fn = norm1(10 * tmp)
        rho = 2
        new_prox = absorb_lin_op(fn)[0]
        x = new_prox.prox(rho, v.copy())
        cvx_x = cvx.Variable(10)
        prob = cvx.Problem(cvx.Minimize(cvx.sum_squares(cvx_x - v) + cvx.norm(10 * cvx_x, 1)))
        prob.solve()
        self.assertItemsAlmostEqual(x, cvx_x.value, places=3)

        val = np.arange(10)
        fn = norm1(10 * tmp, c=val, b=val, gamma=0.01)
        rho = 2
        new_prox = absorb_lin_op(fn)[0]
        x = new_prox.prox(rho, v.copy())
        cvx_x = cvx.Variable(10)
        prob = cvx.Problem(cvx.Minimize(cvx.sum_squares(cvx_x - v) +
                                        cvx.norm(10 * cvx_x - val, 1) + 10 * val.T * \
                                                 cvx_x + cvx.sum_squares(cvx_x)
                                        ))
        prob.solve()
        self.assertItemsAlmostEqual(x, cvx_x.value, places=2)

        # sum_entries
        tmp = Variable(10)
        v = np.arange(10) * 1.0 - 5.0

        fn = sum_entries(sum([10 * tmp, mul_elemwise(v, tmp)]))

        funcs = absorb.absorb_all_lin_ops([fn])
        c = __builtins__['sum']([func.c for func in funcs])
        self.assertItemsAlmostEqual(c, v + 10, places=3)
示例#12
0
    def test_absorb_lin_op(self):
        """Test absorb lin op operator.
        """
        # norm1.
        tmp = Variable(10)
        v = np.arange(10) * 1.0 - 5.0

        fn = norm1(mul_elemwise(-v, tmp), alpha=5.)
        rho = 2
        new_prox = absorb_lin_op(fn)[0]
        x = new_prox.prox(rho, v.copy())
        self.assertItemsAlmostEqual(
            x,
            np.sign(v) * np.maximum(np.abs(v) - 5. * np.abs(v) / rho, 0))

        fn = norm1(mul_elemwise(-v, mul_elemwise(2 * v, tmp)), alpha=5.)
        rho = 2
        new_prox = absorb_lin_op(fn)[0]
        x = new_prox.prox(rho, v.copy())
        self.assertItemsAlmostEqual(
            x,
            np.sign(v) * np.maximum(np.abs(v) - 5. * np.abs(v) / rho, 0))
        new_prox = absorb_lin_op(new_prox)[0]
        x = new_prox.prox(rho, v.copy())
        new_v = 2 * v * v
        self.assertItemsAlmostEqual(
            x,
            np.sign(new_v) *
            np.maximum(np.abs(new_v) - 5. * np.abs(new_v) / rho, 0))

        # nonneg.
        tmp = Variable(10)
        v = np.arange(10) * 1.0 - 5.0

        fn = nonneg(mul_elemwise(-v, tmp), alpha=5.)
        rho = 2
        new_prox = absorb_lin_op(fn)[0]
        x = new_prox.prox(rho, v.copy())
        self.assertItemsAlmostEqual(x, fn.prox(rho, -np.abs(v)))

        # sum_squares.
        tmp = Variable(10)
        v = np.arange(10) * 1.0 - 5.0

        alpha = 5.
        val = np.arange(10)
        fn = sum_squares(mul_elemwise(-v, tmp), alpha=alpha, c=val)
        rho = 2
        new_prox = absorb_lin_op(fn)[0]
        x = new_prox.prox(rho, v.copy())

        cvx_x = cvx.Variable(10)
        prob = cvx.Problem(
            cvx.Minimize(
                cvx.sum_squares(cvx_x - v) * (rho / 2) +
                5 * cvx.sum_squares(cvx.mul_elemwise(-v, cvx_x)) +
                (val * -v).T * cvx_x))
        prob.solve()
        self.assertItemsAlmostEqual(x, cvx_x.value, places=3)

        # Test scale.
        tmp = Variable(10)
        v = np.arange(10) * 1.0 - 5.0

        fn = norm1(10 * tmp)
        rho = 2
        new_prox = absorb_lin_op(fn)[0]
        x = new_prox.prox(rho, v.copy())
        cvx_x = cvx.Variable(10)
        prob = cvx.Problem(
            cvx.Minimize(cvx.sum_squares(cvx_x - v) + cvx.norm(10 * cvx_x, 1)))
        prob.solve()
        self.assertItemsAlmostEqual(x, cvx_x.value, places=3)

        val = np.arange(10)
        fn = norm1(10 * tmp, c=val, b=val, gamma=0.01)
        rho = 2
        new_prox = absorb_lin_op(fn)[0]
        x = new_prox.prox(rho, v.copy())
        cvx_x = cvx.Variable(10)
        prob = cvx.Problem(cvx.Minimize(cvx.sum_squares(cvx_x - v) +
                                        cvx.norm(10 * cvx_x - val, 1) + 10 * val.T * \
                                                 cvx_x + cvx.sum_squares(cvx_x)
                                        ))
        prob.solve()
        self.assertItemsAlmostEqual(x, cvx_x.value, places=2)

        # sum_entries
        tmp = Variable(10)
        v = np.arange(10) * 1.0 - 5.0

        fn = sum_entries(sum([10 * tmp, mul_elemwise(v, tmp)]))

        funcs = absorb.absorb_all_lin_ops([fn])
        c = __builtins__['sum']([func.c for func in funcs])
        self.assertItemsAlmostEqual(c, v + 10, places=3)
示例#13
0
    def test_op_overloading(self):
        """Test operator overloading.
        """
        # Multiplying by a scalar.

        # Forward.
        var = Variable((2, 5))
        W = np.arange(10)
        W = np.reshape(W, (2, 5))
        fn = -2 * mul_elemwise(W, var)
        fn = CompGraph(fn)
        x = W.copy()
        out = np.zeros(x.shape)
        fn.forward(x.flatten(), out)
        self.assertItemsAlmostEqual(out, -2 * W * W)

        # Adjoint.
        x = W.copy()
        out = np.zeros(x.shape).flatten()
        fn.adjoint(x, out)
        self.assertItemsAlmostEqual(out, -2 * W * W)

        # Forward.
        var = Variable((2, 5))
        W = np.arange(10)
        W = np.reshape(W, (2, 5))
        fn = mul_elemwise(W, var) * 0.5
        fn = CompGraph(fn)
        x = W.copy()
        out = np.zeros(x.shape)
        fn.forward(x.flatten(), out)
        self.assertItemsAlmostEqual(out, W * W / 2.)

        # Adjoint.
        x = W.copy()
        out = np.zeros(x.shape).flatten()
        fn.adjoint(x, out)
        self.assertItemsAlmostEqual(out, W * W / 2.)

        # Dividing by a scalar.
        # Forward.
        var = Variable((2, 5))
        W = np.arange(10)
        W = np.reshape(W, (2, 5))
        fn = mul_elemwise(W, var) / 2
        fn = CompGraph(fn)
        x = W.copy()
        out = np.zeros(x.shape)
        fn.forward(x, out)
        self.assertItemsAlmostEqual(out, W * W / 2.)

        # Adding lin ops.
        # Forward.
        x = Variable((2, 5))
        W = np.arange(10)
        W = np.reshape(W, (2, 5))
        fn = mul_elemwise(W, x)
        fn = fn + x + x
        self.assertEquals(len(fn.input_nodes), 3)
        fn = CompGraph(fn)
        x = W.copy()
        out = np.zeros(fn.shape)
        fn.forward(x, out)
        self.assertItemsAlmostEqual(out, W * W + 2 * W)

        # Adjoint.
        x = W.copy()
        out = np.zeros(x.shape).flatten()
        fn.adjoint(x, out)
        self.assertItemsAlmostEqual(out, W * W + 2 * W)

        # Adding in a constant.
        # CompGraph should ignore the constant.
        x = Variable((2, 5))
        W = np.arange(10)
        W = np.reshape(W, (2, 5))
        fn = mul_elemwise(W, x)
        fn = fn + x + W
        self.assertEquals(len(fn.input_nodes), 3)
        fn = CompGraph(fn)
        x = W.copy()
        out = np.zeros(fn.shape)
        fn.forward(x, out)
        self.assertItemsAlmostEqual(out, W * W + W)

       # Subtracting lin ops.
        # Forward.
        x = Variable((2, 5))
        W = np.arange(10)
        W = np.reshape(W, (2, 5))
        fn = -mul_elemwise(W, x)
        fn = x + x - fn
        self.assertEquals(len(fn.input_nodes), 3)
        fn = CompGraph(fn)
        x = W.copy()
        out = np.zeros(fn.shape)
        fn.forward(x, out)
        self.assertItemsAlmostEqual(out, W * W + 2 * W)

        # Adjoint.
        x = W.copy()
        out = np.zeros(x.shape).flatten()
        fn.adjoint(x, out)
        self.assertItemsAlmostEqual(out, W * W + 2 * W)