コード例 #1
0
ファイル: test_basic.py プロジェクト: thiboeri/Theano
    def _testDS(self,
                op,
                array1=numpy.array([[1., 0], [3, 0], [0, 6]]),
                array2=numpy.asarray([[0, 2.], [0, 4], [5, 0]])):
        for mtype in _mtypes:
            a = mtype(array1)
            aR = as_sparse_variable(a)
            self.assertFalse(aR.data is a)
            self.assertTrue(_is_sparse(a))
            self.assertTrue(_is_sparse_variable(aR))

            b = numpy.asarray(array2)
            bR = tensor.as_tensor_variable(b)
            self.assertFalse(bR.data is b)
            self.assertTrue(_is_dense(b))
            self.assertTrue(_is_dense_variable(bR))

            apb = op(aR, bR)

            self.assertTrue(apb.type.dtype == aR.type.dtype, apb.type.dtype)
            self.assertTrue(apb.type.dtype == bR.type.dtype, apb.type.dtype)

            val = eval_outputs([apb])
            self.assertTrue(val.shape == (3, 2))
            if op is add:
                self.assertTrue(_is_dense_variable(apb))
                self.assertTrue(numpy.all(val == (a + b)))
                ans = numpy.array([[1., 2], [3, 4], [5, 6]])
                self.assertTrue(numpy.all(val == ans))
            elif op is mul:
                self.assertTrue(_is_sparse_variable(apb))
                ans = numpy.array([[1, 0], [9, 0], [0, 36]])
                self.assertTrue(numpy.all(val.todense() == (a.multiply(b))))
                self.assertTrue(numpy.all(val.todense() == ans))
コード例 #2
0
    def test_basicSS(self):
        for mtype in _mtypes:
            x = as_sparse_variable(mtype((500, 3)))
            x.data[(10, 1)] = 1
            x.data[(20, 2)] = 2
            self.assertTrue(_is_sparse_variable(x))

            xT = x.T
            self.assertTrue(_is_sparse_variable(xT))

            zop = true_dot(x, xT)
            self.assertTrue(_is_sparse_variable(zop))
            z = eval_outputs([zop])
            self.assertTrue(_is_sparse(z))
            self.assertTrue(z.shape == (500, 500))
            self.assertTrue(type(z) is mtype)

            w = mtype((500, 500))
            w[(10, 10)] = 1
            w[(20, 20)] = 4
            self.assertTrue(z.shape == w.shape)
            self.assertTrue(type(z) == type(w))
            self.assertTrue(z.dtype == w.dtype)

            #self.assertTrue(z == w)
            self.assertTrue(abs(z - w).nnz == 0)

            z = z.todense()
            w = w.todense()
            self.assertTrue((z == w).all() == True)
コード例 #3
0
ファイル: truedot.py プロジェクト: HaniAlmousli/Theano
    def test_basicSD(self):
        for mtype in _mtypes:
            x = as_sparse_variable(mtype((500,3)))
            x.data[(10, 1)] = 1
            x.data[(20, 2)] = 2
            self.assertTrue(_is_sparse_variable(x))

            y = tensor.as_tensor_variable([[1., 2], [3, 4], [2, 1]])
            self.assertTrue(_is_dense_variable(y))

            zop = true_dot(x,y)
            self.assertTrue(_is_sparse_variable(zop))
            z = eval_outputs([zop])
            self.assertTrue(_is_sparse(z))
            self.assertTrue(z.shape == (500,2))
            self.assertTrue(type(z) is mtype)

            w = mtype((500,2))
            w[(10, 0)] = 3.
            w[(20, 0)] = 4
            w[(10, 1)] = 4
            w[(20, 1)] = 2
            self.assertTrue(z.shape == w.shape)
            self.assertTrue(type(z) == type(w))
            self.assertTrue(z.dtype == w.dtype)

            #self.assertTrue(z == w)
            self.assertTrue(abs(z-w).nnz == 0)

            z = z.todense()
            w = w.todense()
            self.assertTrue((z == w).all() == True)
コード例 #4
0
    def test_basicSD(self):
        for mtype in _mtypes:
            x = as_sparse_variable(mtype((500, 3)))
            x.data[(10, 1)] = 1
            x.data[(20, 2)] = 2
            self.assertTrue(_is_sparse_variable(x))

            y = tensor.as_tensor_variable([[1., 2], [3, 4], [2, 1]])
            self.assertTrue(_is_dense_variable(y))

            zop = true_dot(x, y)
            self.assertTrue(_is_sparse_variable(zop))
            z = eval_outputs([zop])
            self.assertTrue(_is_sparse(z))
            self.assertTrue(z.shape == (500, 2))
            self.assertTrue(type(z) is mtype)

            w = mtype((500, 2))
            w[(10, 0)] = 3.
            w[(20, 0)] = 4
            w[(10, 1)] = 4
            w[(20, 1)] = 2
            self.assertTrue(z.shape == w.shape)
            self.assertTrue(type(z) == type(w))
            self.assertTrue(z.dtype == w.dtype)

            #self.assertTrue(z == w)
            self.assertTrue(abs(z - w).nnz == 0)

            z = z.todense()
            w = w.todense()
            self.assertTrue((z == w).all() == True)
コード例 #5
0
ファイル: truedot.py プロジェクト: HaniAlmousli/Theano
    def test_basicSS(self):
        for mtype in _mtypes:
            x = as_sparse_variable(mtype((500,3)))
            x.data[(10, 1)] = 1
            x.data[(20, 2)] = 2
            self.assertTrue(_is_sparse_variable(x))

            xT = x.T
            self.assertTrue(_is_sparse_variable(xT))

            zop = true_dot(x,xT)
            self.assertTrue(_is_sparse_variable(zop))
            z = eval_outputs([zop])
            self.assertTrue(_is_sparse(z))
            self.assertTrue(z.shape == (500,500))
            self.assertTrue(type(z) is mtype)

            w = mtype((500,500))
            w[(10, 10)] = 1
            w[(20, 20)] = 4
            self.assertTrue(z.shape == w.shape)
            self.assertTrue(type(z) == type(w))
            self.assertTrue(z.dtype == w.dtype)

            #self.assertTrue(z == w)
            self.assertTrue(abs(z-w).nnz == 0)

            z = z.todense()
            w = w.todense()
            self.assertTrue((z == w).all() == True)
コード例 #6
0
ファイル: test_basic.py プロジェクト: daien/Theano
    def _testDS(
        self, op, array1=numpy.array([[1.0, 0], [3, 0], [0, 6]]), array2=numpy.asarray([[0, 2.0], [0, 4], [5, 0]])
    ):
        for mtype in _mtypes:
            a = mtype(array1)
            aR = as_sparse_variable(a)
            self.assertFalse(aR.data is a)
            self.assertTrue(_is_sparse(a))
            self.assertTrue(_is_sparse_variable(aR))

            b = numpy.asarray(array2)
            bR = tensor.as_tensor_variable(b)
            self.assertFalse(bR.data is b)
            self.assertTrue(_is_dense(b))
            self.assertTrue(_is_dense_variable(bR))

            apb = op(aR, bR)

            self.assertTrue(apb.type.dtype == aR.type.dtype, apb.type.dtype)
            self.assertTrue(apb.type.dtype == bR.type.dtype, apb.type.dtype)

            val = eval_outputs([apb])
            self.assertTrue(val.shape == (3, 2))
            if op is add:
                self.assertTrue(_is_dense_variable(apb))
                self.assertTrue(numpy.all(val == (a + b)))
                ans = numpy.array([[1.0, 2], [3, 4], [5, 6]])
                self.assertTrue(numpy.all(val == ans))
            elif op is mul:
                self.assertTrue(_is_sparse_variable(apb))
                ans = numpy.array([[1, 0], [9, 0], [0, 36]])
                self.assertTrue(numpy.all(val.todense() == (a.multiply(b))))
                self.assertTrue(numpy.all(val.todense() == ans))
コード例 #7
0
ファイル: truedot.py プロジェクト: HaniAlmousli/Theano
 def grad(self, inp, grads):
     x, y = inp
     gz, = grads
     assert _is_sparse_variable(gz)
     assert _is_sparse_variable(x)
     rval = [true_dot(gz, y.T), true_dot(x.T, gz)]
     if _is_dense_variable(y):
         if self.grad_preserves_dense:
             rval[1] = dense_from_sparse(rval[1])
     return rval
コード例 #8
0
 def grad(self, inp, grads):
     x, y = inp
     gz, = grads
     assert _is_sparse_variable(gz)
     assert _is_sparse_variable(x)
     rval = [true_dot(gz, y.T), true_dot(x.T, gz)]
     if _is_dense_variable(y):
         if self.grad_preserves_dense:
             rval[1] = dense_from_sparse(rval[1])
     return rval
コード例 #9
0
ファイル: sp2.py プロジェクト: jsalvatier/Theano-1
class SamplingDot(gof.op.Op):
    """
    Operand for calculating the dot product DOT(X, Y) = Z when you
    only want to calculate a subset of Z. It is equivalent to P o (X
    . Y) where o is the element-wise product, X and Y operands of the
    dot product and P is a matrix that contains 1 when the
    corresponding element of Z should be calculated and 0 when it
    shouldn't. Note that SamplingDot has a different interface than
    DOT because SamplingDot requires X to be a MxK matrix while Y is a
    NxK matrix instead of the usual KxN matrix.

    It will work if the pattern is not binary value, but if the
    pattern doesn't have a high sparsity proportion it will be slower
    then a more optimized dot followed by a normal elemwise
    multiplication.

    """
    def __eq__(self, other):
        return type(self) == type(other)

    def __hash__(self):
        return hash(type(self))

    def __str__(self):
        return 'SamplingDot'

    def make_node(self, x, y, p):
        x = tensor.as_tensor_variable(x)
        y = tensor.as_tensor_variable(y)

        if not _is_sparse_variable(p):
            raise TypeError(p)

        #TODO: use it.
        dtype_out = scalar.upcast(x.type.dtype, y.type.dtype, p.type.dtype)

        return gof.Apply(self, [x, y, p], [p.type()])

    def perform(self, node, (x, y, p), (out, )):
        if _is_sparse_variable(x):
            raise TypeError(x)

        if _is_sparse_variable(y):
            raise TypeError(y)

        if not _is_sparse(p):
            raise TypeError(p)

        rval = p.__class__(p.multiply(numpy.dot(x, y.T)))

        out[0] = rval
コード例 #10
0
ファイル: sp2.py プロジェクト: jsalvatier/Theano-1
def local_structured_add_s_v(node):
    if node.op == structured_add_s_v:
        x, y = node.inputs

        x_is_sparse_variable = _is_sparse_variable(x)
        #y_is_sparse_variable = _is_sparse_variable(y)

        if x_is_sparse_variable:
            svar = x
            dvar = y
        else:
            svar = y
            dvar = x

        if dvar.type.ndim != 1:
            return False
        elif svar.type.format == 'csr':
            CSx = CSR
            structured_add_s_v_csx = structured_add_s_v_csr
        else:
            return False

        s_val, s_ind, s_ptr, s_shape = csm_properties(svar)

        c_data = structured_add_s_v_csx(s_val, s_ind, s_ptr, dvar)

        return [CSx(c_data, s_ind, s_ptr, s_shape)]

    return False
コード例 #11
0
ファイル: sp2.py プロジェクト: jsalvatier/Theano-1
def local_mul_s_v(node):
    if node.op == mul_s_v:
        x, y = node.inputs

        x_is_sparse_variable = _is_sparse_variable(x)

        if x_is_sparse_variable:
            svar = x
            dvar = y
        else:
            svar = y
            dvar = x

        if dvar.type.ndim != 1:
            return False
        elif svar.type.format == 'csr':
            CSx = CSR
            mul_s_v_csx = mul_s_v_csr
        else:
            return False

        s_val, s_ind, s_ptr, s_shape = csm_properties(svar)

        c_data = mul_s_v_csx(s_val, s_ind, s_ptr, dvar)

        return [CSx(c_data, s_ind, s_ptr, s_shape)]

    return False
コード例 #12
0
ファイル: sp2.py プロジェクト: lberrada/Theano
def local_structured_add_s_v(node):
    if node.op == structured_add_s_v:
        x, y = node.inputs

        x_is_sparse_variable = _is_sparse_variable(x)
        #y_is_sparse_variable = _is_sparse_variable(y)

        if x_is_sparse_variable:
            svar = x
            dvar = y
        else:
            svar = y
            dvar = x

        if dvar.type.ndim != 1:
            return False
        elif svar.type.format == 'csr':
            CSx = CSR
            structured_add_s_v_csx = structured_add_s_v_csr
        else:
            raise NotImplemented()

        s_val, s_ind, s_ptr, s_shape = csm_properties(svar)

        c_data = structured_add_s_v_csx(s_val, s_ind, s_ptr, dvar)

        return [CSx(c_data, s_ind, s_ptr, s_shape)]

    return False
コード例 #13
0
ファイル: sp2.py プロジェクト: lberrada/Theano
def local_mul_s_d(node):
    if node.op == mul_s_d:
        x, y = node.inputs

        x_is_sparse_variable = _is_sparse_variable(x)
        # y_is_sparse_variable = _is_sparse_variable(y)

        if x_is_sparse_variable:
            svar = x
            dvar = y
        else:
            svar = y
            dvar = x

        if dvar.type.ndim != 2:
            return False
        if svar.type.format == 'csc':
            CSx = CSC
            mul_s_d_csx = mul_s_d_csc
        elif svar.type.format == 'csr':
            CSx = CSR
            mul_s_d_csx = mul_s_d_csr
        else:
            raise NotImplemented()

        c_data = mul_s_d_csx(csm_data(svar), csm_indices(svar),
                             csm_indptr(svar), dvar)

        return [CSx(c_data, csm_indices(svar), csm_indptr(svar),
                    csm_shape(svar))]

    return False
コード例 #14
0
ファイル: sp2.py プロジェクト: jsalvatier/Theano-1
def local_mul_s_d(node):
    if node.op == mul_s_d:
        x, y = node.inputs

        x_is_sparse_variable = _is_sparse_variable(x)
        # y_is_sparse_variable = _is_sparse_variable(y)

        if x_is_sparse_variable:
            svar = x
            dvar = y
        else:
            svar = y
            dvar = x

        if dvar.type.ndim != 2:
            return False
        if svar.type.format == 'csc':
            CSx = CSC
            mul_s_d_csx = mul_s_d_csc
        elif svar.type.format == 'csr':
            CSx = CSR
            mul_s_d_csx = mul_s_d_csr
        else:
            raise NotImplemented()

        c_data = mul_s_d_csx(csm_data(svar), csm_indices(svar),
                             csm_indptr(svar), dvar)

        return [
            CSx(c_data, csm_indices(svar), csm_indptr(svar), csm_shape(svar))
        ]

    return False
コード例 #15
0
def true_dot(x, y, grad_preserves_dense=True):
    """
    @todo: Maybe the triple-transposition formulation (when x is dense)
    is slow. See if there is a direct way to do this.
    """
    if hasattr(x, 'getnnz'): x = as_sparse_variable(x)
    if hasattr(y, 'getnnz'): y = as_sparse_variable(y)

    x_is_sparse_variable = _is_sparse_variable(x)
    y_is_sparse_variable = _is_sparse_variable(y)
    if not x_is_sparse_variable and not y_is_sparse_variable:
        raise TypeError()
    if x_is_sparse_variable:
        return TrueDot(grad_preserves_dense)(x, y)
    else:
        assert y_is_sparse_variable
        return transpose(TrueDot(grad_preserves_dense)(y.T, x.T))
コード例 #16
0
ファイル: truedot.py プロジェクト: HaniAlmousli/Theano
def true_dot(x, y, grad_preserves_dense=True):
    """
    @todo: Maybe the triple-transposition formulation (when x is dense)
    is slow. See if there is a direct way to do this.
    """
    if hasattr(x, 'getnnz'): x = as_sparse_variable(x)
    if hasattr(y, 'getnnz'): y = as_sparse_variable(y)

    x_is_sparse_variable = _is_sparse_variable(x)
    y_is_sparse_variable = _is_sparse_variable(y)
    if not x_is_sparse_variable and not y_is_sparse_variable:
        raise TypeError()
    if x_is_sparse_variable:
        return TrueDot(grad_preserves_dense)(x, y)
    else:
        assert y_is_sparse_variable
        return transpose(TrueDot(grad_preserves_dense)(y.T, x.T))
コード例 #17
0
ファイル: sp2.py プロジェクト: jsalvatier/Theano-1
    def make_node(self, x, y, p):
        x = tensor.as_tensor_variable(x)
        y = tensor.as_tensor_variable(y)

        if not _is_sparse_variable(p):
            raise TypeError(p)

        #TODO: use it.
        dtype_out = scalar.upcast(x.type.dtype, y.type.dtype, p.type.dtype)

        return gof.Apply(self, [x, y, p], [p.type()])
コード例 #18
0
ファイル: sp2.py プロジェクト: lberrada/Theano
    def make_node(self, x, y, p):
        x = tensor.as_tensor_variable(x)
        y = tensor.as_tensor_variable(y)

        if not _is_sparse_variable(p):
            raise TypeError(p)

        #TODO: use it.
        dtype_out = scalar.upcast(x.type.dtype, y.type.dtype, p.type.dtype)

        return gof.Apply(self, [x, y, p], [p.type()])
コード例 #19
0
    def test_basicDS(self):
        for mtype in _mtypes:
            x = as_sparse_variable(mtype((500, 3)))
            x.data[(10, 1)] = 1
            x.data[(20, 2)] = 2
            self.assertTrue(_is_sparse_variable(x))

            y = tensor.as_tensor_variable([[1., 2], [3, 4], [2, 1]])
            self.assertTrue(_is_dense_variable(y))

            x.data = x.data.T
            y.data = y.data.T

            zop = true_dot(y, x)
            zop = transpose(true_dot(y, x))
            self.assertTrue(_is_sparse_variable(zop))
            z = eval_outputs([zop])
            self.assertTrue(_is_sparse(z))
            self.assertTrue(z.shape == (500, 2))
            #            self.assertTrue(type(z) is mtype)

            w = mtype((500, 2))
            w[(10, 0)] = 3.
            w[(20, 0)] = 4
            w[(10, 1)] = 4
            w[(20, 1)] = 2
            self.assertTrue(z.shape == w.shape)
            # Type should switch from csr to csc and vice-versa, so don't perform this test
            #self.assertTrue(type(z) == type(w))
            self.assertTrue(z.dtype == w.dtype)

            # Type should switch from csr to csc and vice-versa, so don't perform this test
            #self.assertTrue(z == w)
            self.assertTrue(abs(z - w).nnz == 0)

            z = z.todense()
            w = w.todense()
            self.assertTrue((z == w).all() == True)
コード例 #20
0
ファイル: truedot.py プロジェクト: HaniAlmousli/Theano
    def test_basicDS(self):
        for mtype in _mtypes:
            x = as_sparse_variable(mtype((500,3)))
            x.data[(10, 1)] = 1
            x.data[(20, 2)] = 2
            self.assertTrue(_is_sparse_variable(x))

            y = tensor.as_tensor_variable([[1., 2], [3, 4], [2, 1]])
            self.assertTrue(_is_dense_variable(y))

            x.data = x.data.T
            y.data = y.data.T

            zop = true_dot(y, x)
            zop = transpose(true_dot(y, x))
            self.assertTrue(_is_sparse_variable(zop))
            z = eval_outputs([zop])
            self.assertTrue(_is_sparse(z))
            self.assertTrue(z.shape == (500,2))
#            self.assertTrue(type(z) is mtype)

            w = mtype((500,2))
            w[(10, 0)] = 3.
            w[(20, 0)] = 4
            w[(10, 1)] = 4
            w[(20, 1)] = 2
            self.assertTrue(z.shape == w.shape)
            # Type should switch from csr to csc and vice-versa, so don't perform this test
            #self.assertTrue(type(z) == type(w))
            self.assertTrue(z.dtype == w.dtype)

            # Type should switch from csr to csc and vice-versa, so don't perform this test
            #self.assertTrue(z == w)
            self.assertTrue(abs(z-w).nnz == 0)

            z = z.todense()
            w = w.todense()
            self.assertTrue((z == w).all() == True)
コード例 #21
0
ファイル: truedot.py プロジェクト: HaniAlmousli/Theano
    def make_node(self, x, y):
        """
        :note: Because of trickiness of implementing, we assume that the left argument x is SparseVariable (not dense)
        """
        if x.type.dtype != y.type.dtype:
            raise NotImplementedError()

        if not _is_sparse_variable(x):
            raise TypeError(x)

        # These are the conversions performed by scipy.sparse.dot
        if x.type.format == "csc" or x.type.format == "coo":
            myformat = "csc"
        elif x.type.format == "csr":
            myformat = "csr"
        else:
            raise NotImplementedError()

        inputs = [x, y]    # Need to convert? e.g. assparse
        outputs = [SparseType(dtype = x.type.dtype, format = myformat).make_variable()]
        return gof.Apply(self, inputs, outputs)
コード例 #22
0
    def make_node(self, x, y):
        """
        :note: Because of trickiness of implementing, we assume that the left argument x is SparseVariable (not dense)
        """
        if x.type.dtype != y.type.dtype:
            raise NotImplementedError()

        if not _is_sparse_variable(x):
            raise TypeError(x)

        # These are the conversions performed by scipy.sparse.dot
        if x.type.format == "csc" or x.type.format == "coo":
            myformat = "csc"
        elif x.type.format == "csr":
            myformat = "csr"
        else:
            raise NotImplementedError()

        inputs = [x, y]  # Need to convert? e.g. assparse
        outputs = [
            SparseType(dtype=x.type.dtype, format=myformat).make_variable()
        ]
        return gof.Apply(self, inputs, outputs)
コード例 #23
0
ファイル: sp2.py プロジェクト: jsalvatier/Theano-1
        assert y.type.ndim == 1

        if x.type.dtype != y.type.dtype:
            raise NotImplementedError()
        return gof.Apply(self, [x, y], [
            SparseType(dtype=x.type.dtype,
                       format=x.type.format).make_variable()
        ])

    def perform(self, node, (x, y), (out, )):
        assert _is_sparse(x) and not _is_sparse(y)
        assert x.shape[1] == y.shape[0]
        out[0] = x.__class__(x.toarray() * y)

    def grad(self, (x, y), (gz, )):
        assert _is_sparse_variable(x) and _is_dense_variable(y)
        assert _is_sparse_variable(gz)
        return mul_s_v(gz, y), sp_sum(x * gz, axis=0, sparse_grad=True)


mul_s_v = MulSV()


class MulSVCSR(gof.Op):
    def __eq__(self, other):
        return (type(self) == type(other))

    def __hash__(self):
        return hash(type(self))

    def make_node(self, a_data, a_indices, a_indptr, b):
コード例 #24
0
ファイル: sp2.py プロジェクト: lberrada/Theano
        assert y.type.ndim == 1

        if x.type.dtype != y.type.dtype:
            raise NotImplementedError()
        return gof.Apply(self,
                         [x, y],
                         [SparseType(dtype=x.type.dtype,
                                 format=x.type.format).make_variable()])

    def perform(self, node, (x, y), (out, )):
        assert _is_sparse(x) and not _is_sparse(y)
        assert x.shape[1] == y.shape[0]
        out[0] = x.__class__(x + (x.toarray() != 0) * y)

    def grad(self, (x, y), (gz,)):
        assert _is_sparse_variable(x) and _is_sparse_variable(y)
        assert _is_sparse_variable(gz)
        return gz, gz
structured_add_s_v = StructuredAddSV()


class StrucutedAddSVCSR(gof.Op):
    def __eq__(self, other):
        return (type(self) == type(other))

    def __hash__(self):
        return hash(type(self))

    def make_node(self, a_data, a_indices, a_indptr, b):
        assert b.type.ndim == 1
        return gof.Apply(self, [a_data, a_indices, a_indptr, b],
コード例 #25
0
ファイル: sp2.py プロジェクト: jsalvatier/Theano-1
        assert y.type.ndim == 1

        if x.type.dtype != y.type.dtype:
            raise NotImplementedError()
        return gof.Apply(self,
                         [x, y],
                         [SparseType(dtype=x.type.dtype,
                                 format=x.type.format).make_variable()])

    def perform(self, node, (x, y), (out, )):
        assert _is_sparse(x) and not _is_sparse(y)
        assert x.shape[1] == y.shape[0]
        out[0] = x.__class__(x.toarray() * y)

    def grad(self, (x, y), (gz,)):
        assert _is_sparse_variable(x) and _is_dense_variable(y)
        assert _is_sparse_variable(gz)
        return mul_s_v(gz, y), sp_sum(x * gz, axis=0, sparse_grad=True)
mul_s_v = MulSV()


class MulSVCSR(gof.Op):
    def __eq__(self, other):
        return (type(self) == type(other))

    def __hash__(self):
        return hash(type(self))

    def make_node(self, a_data, a_indices, a_indptr, b):
        assert b.type.ndim == 1
        return gof.Apply(self, [a_data, a_indices, a_indptr, b],