mnick / scikit-tensor

Python library for multilinear algebra and tensor factorizations
GNU General Public License v3.0
401 stars 113 forks source link

TypeError when result of sptensor.ttv(vectors) is a sptensor #2

Closed panisson closed 10 years ago

panisson commented 10 years ago

When applying ttv (tensor times vector) between a sparse tensor and a set of vectors, if the result is a sparse tensor, I get the following error:

"TypeError: arange: scalar arguments expected instead of a tuple."

The error can be reproduced with this test case:

    def test_ttv():
        subs = (
            array([0, 1, 0, 5, 7, 8]),
            array([2, 0, 4, 5, 3, 9]),
            array([0, 1, 2, 2, 1, 0])
        )
        vals = array([1, 1, 1, 1, 1, 1])
        S = sptensor(subs, vals, shape=[10, 10, 3])

        sttv = S.ttv((zeros(10), zeros(10)), modes=[0, 1])
        assert_equal(type(sttv), sptensor)
        assert_true((allclose(zeros(3), sttv.vals)))
        assert_true((allclose(np.arange(3), sttv.subs)))
panisson commented 10 years ago

The following patch could work as a solution to this problem:

    diff --git a/sktensor/sptensor.py b/sktensor/sptensor.py
    index 21baf74..0eacfb6 100644
    --- a/sktensor/sptensor.py
    +++ b/sktensor/sptensor.py
    @@ -134,9 +134,9 @@ class sptensor(tensor_mixin):

             # Case 2: result is a vector
             if len(remdims) == 1:
    -            c = accum(nsubs, nvals, shape=nshp)
    +            c, s = accum(nsubs, nvals, shape=nshp, with_subs=True)
                 if len(np.nonzero(c)[0]) <= 0.5 * prod(nshp):
    -                return sptensor(arange(nshp), c)
    +                return sptensor(s, c)
                 else:
                     return c

combined with this correction on the function accum:

    diff --git a/sktensor/utils.py b/sktensor/utils.py
    index b76ad83..ae6fa82 100644
    --- a/sktensor/utils.py
    +++ b/sktensor/utils.py
    @@ -24,7 +24,7 @@ def accum(subs, vals, func=np.sum, sorted=False, shape=None, with_subs=False):

         # return results
         if with_subs:
    -        return nvals, subs[idx[:-1]]
    +        return nvals, tuple(sub[idx[:-1]] for sub in subs)
         else:
             return nvals
mnick commented 10 years ago

Thanks for the bug report. The bug occured because of some API changes for sptensor.

I incorporated your fix in 10116c82fc44caeaf4bb0408333f9af96d454985 and the test case in 7a7502df6f3d547f9d293dd43c8f1165b718609e.

panisson commented 10 years ago

Thanks for the fix, Maximilian.

I have another error, that seems related to this, since it occurs when ttv returns a sptensor. It can be reproduced with this test case:

def test_uttkrp():
    subs, vals, shape = mysetup()
    S = sptensor(subs, vals, shape)
    U = []
    for shp in (25, 11, 18, 7, 2):
        U.append(np.zeros((shp, 5)))
    SU = S.uttkrp(U, mode=0)
    assert_equal(SU.shape, (25, 5))

The error is "TypeError: float() argument must be a string or a number", and it happens in sptensor.py, line 191, in uttkrp:

    V[:, r] = self.ttv(Z, mode, without=True)

It seems that, when the result of ttv is a sptensor, it cannot be assigned to V using this operation.

Let me know if I should open a new issue report or if you will reopen this one.

mnick commented 10 years ago

Please open a new issue, as this is a different issue. Thank you!