Permalink
Browse files

Merge branch 'release-0.1.2'

  • Loading branch information...
2 parents c7a26f3 + ebf1dcb commit f1d48dc9a774904994d02d6e420c3568553ffc29 @nzhiltsov committed Feb 24, 2013
Showing with 76 additions and 43 deletions.
  1. +2 −2 README.md
  2. +9 −2 commonFunctions.py
  3. +21 −3 commonFunctionsTest.py
  4. +16 −25 extrescal.py
  5. +5 −0 extrescalFunctions.py
  6. +22 −2 extrescalFunctionsTest.py
  7. +1 −9 rescal.py
View
@@ -4,11 +4,11 @@ Ext-RESCAL
Scalable Tensor Factorization
------------------------------
-Ext-RESCAL is a memory efficient implementation of the [RESCAL algorithm](http://www.cip.ifi.lmu.de/~nickel/). It is written in Python and relies on the SciPy Sparse module.
+Ext-RESCAL is a memory efficient implementation of the [RESCAL algorithm](http://www.cip.ifi.lmu.de/~nickel/data/slides-icml2011.pdf). It is written in Python and relies on the SciPy Sparse module.
Current Version
------------
-[0.1.1](https://github.com/nzhiltsov/Ext-RESCAL/archive/0.1.1.zip)
+[0.1.2](https://github.com/nzhiltsov/Ext-RESCAL/archive/0.1.2.zip)
Features
------------
View
@@ -1,4 +1,4 @@
-
+from numpy import dot
def squareFrobeniusNormOfSparse(M):
"""
@@ -8,4 +8,11 @@ def squareFrobeniusNormOfSparse(M):
norm = 0
for i in range(len(rows)):
norm += M[rows[i],cols[i]] ** 2
- return norm
+ return norm
+
+def fitNorm(row, col, Xi, ARk, A):
+ """
+ Computes i,j element of the squared Frobenius norm of the fitting matrix
+ """
+ ARAtValue = dot(ARk[row,:], A[col,:])
+ return (Xi[row, col] - ARAtValue)**2
View
@@ -1,9 +1,11 @@
-from numpy import ones
+from numpy import ones, dot
import numpy as np
from scipy.sparse import coo_matrix
-from commonFunctions import squareFrobeniusNormOfSparse
+from commonFunctions import squareFrobeniusNormOfSparse, fitNorm
+from numpy.linalg.linalg import norm
+from nose.tools import assert_almost_equal
-def test():
+def testSquareFrobeniusNorm():
zeroCount = 2
rowIndices = np.array([1, 2])
colIndices = np.array([0, 0])
@@ -12,4 +14,20 @@ def test():
M = coo_matrix((ones(zeroCount),(rowIndices, colIndices)), shape=(rowSize, colSize), dtype=np.uint8).tolil()
assert squareFrobeniusNormOfSparse(M) == 2
+def testFitNorm():
+ X = coo_matrix((ones(4),([0, 1, 2, 2], [1, 1, 0, 1])), shape=(3, 3), dtype=np.uint8).tolil()
+ n = X.shape[0]
+ A = np.array([[0.9, 0.1],
+ [0.8, 0.2],
+ [0.1, 0.9]])
+ R = np.array([[0.9, 0.1],
+ [0.1, 0.9]])
+ expectedNorm = norm(X - dot(A,dot(R, A.T)))**2
+ ARk = dot(A, R)
+ fits = []
+ for i in xrange(n):
+ for j in xrange(n):
+ fits.append(fitNorm(i, j, X, ARk, A))
+ assert_almost_equal(sum(fits), expectedNorm)
+
View
@@ -7,26 +7,19 @@
import numpy as np
import os
import fnmatch
-from commonFunctions import squareFrobeniusNormOfSparse
-from extrescalFunctions import updateA, updateV
+from commonFunctions import squareFrobeniusNormOfSparse, fitNorm
+from extrescalFunctions import updateA, updateV, matrixFitNormElement
__version__ = "0.1"
__DEF_MAXITER = 50
__DEF_PREHEATNUM = 1
__DEF_INIT = 'nvecs'
__DEF_PROJ = True
-__DEF_CONV = 1e-6
+__DEF_CONV = 1e-5
__DEF_LMBDA = 0
__DEF_EXACT_FIT = False
-def fitNorm(row, col, Xi, ARk, A):
- """
- Computes i,j element of the squared Frobenius norm of the fitting matrix
- """
- ARAtValue = dot(ARk[row,:], A[col,:])
- return (Xi[row, col] - ARAtValue)**2
-
def rescal(X, D, rank, **kwargs):
"""
RESCAL
@@ -129,8 +122,8 @@ def rescal(X, D, rank, **kwargs):
raise 'Projection via QR decomposition is required; pass proj=true'
# initialize V
- Drow, Dcol = D.shape
- V = array(rand(rank, Dcol), dtype=np.float64)
+ DrowSize, DcolSize = D.shape
+ V = array(rand(rank, DcolSize), dtype=np.float64)
# compute factorization
fit = fitchange = fitold = 0
@@ -158,7 +151,7 @@ def rescal(X, D, rank, **kwargs):
fitDAV = 0
if iter > preheatnum:
if lmbda != 0:
- for i in range(len(R)):
+ for i in xrange(len(R)):
regRFit += norm(R[i])**2
regularizedFit = lmbda*(norm(A)**2) + lmbda*regRFit
if lmbda != 0:
@@ -167,20 +160,18 @@ def rescal(X, D, rank, **kwargs):
fitDAV = norm(D - dot(A,V))**2
else :
Drow, Dcol = D.nonzero()
- for ff in range(len(Drow)):
- fitDAV += (D[Drow[ff],Dcol[ff]] - dot(A[Drow[ff],:], V[:, Dcol[ff]]))**2
+ for ff in xrange(len(Drow)):
+ fitDAV += matrixFitNormElement(Drow[ff], Dcol[ff], D, A, V)
if exactfit:
- for i in range(len(R)):
- tensorFit = norm(X[i] - dot(A,dot(R[i], A.T)))**2
+ for i in xrange(len(R)):
+ tensorFit += norm(X[i] - dot(A,dot(R[i], A.T)))**2
else :
- for i in range(len(R)):
+ for i in xrange(len(R)):
ARk = dot(A, R[i])
Xrow, Xcol = X[i].nonzero()
- fits = []
- for rr in range(len(Xrow)):
- fits.append(fitNorm(Xrow[rr], Xcol[rr], X[i], ARk, A))
- tensorFit = sum(fits)
+ for rr in xrange(len(Xrow)):
+ tensorFit += fitNorm(Xrow[rr], Xcol[rr], X[i], ARk, A)
fit = 0.5*tensorFit
fit += regularizedFit
@@ -207,12 +198,12 @@ def __updateR(X, A, lmbda):
At = A.T
if lmbda == 0:
ainv = dot(pinv(dot(At, A)), At)
- for i in range(len(X)):
+ for i in xrange(len(X)):
R.append( dot(ainv, X[i].dot(ainv.T)) )
else :
AtA = dot(At, A)
tmp = inv(kron(AtA, AtA) + lmbda * eye(r**2))
- for i in range(len(X)):
+ for i in xrange(len(X)):
AtXA = dot(At, X[i].dot(A))
R.append( dot(AtXA.flatten(), tmp).reshape(r, r) )
return R
@@ -221,7 +212,7 @@ def __updateR(X, A, lmbda):
def __projectSlices(X, Q):
q = Q.shape[1]
X2 = []
- for i in range(len(X)):
+ for i in xrange(len(X)):
X2.append( dot(Q.T, X[i].dot(Q)) )
return X2
View
@@ -26,3 +26,8 @@ def updateV(A, D, lmbda):
invPart = inv(dot(At, A) + lmbda * eye(rank))
return dot(invPart, At) * D
+def matrixFitNormElement(i, j, D, A, V):
+ """
+ Computes i,j element of the fitting matrix Frobenius norm ||D - A*V||
+ """
+ return (D[i,j] - dot(A[i,:], V[:, j]))**2
View
@@ -1,9 +1,10 @@
from scipy.sparse import coo_matrix
from numpy import ones, dot, eye
import numpy as np
-from extrescalFunctions import updateA, updateV
+from extrescalFunctions import updateA, updateV, matrixFitNormElement
from nose.tools import assert_almost_equal
from numpy.linalg import inv
+from numpy.linalg.linalg import norm
def testUpdateA():
A = np.array([[0.1, 0.1, 0.1],
@@ -59,5 +60,24 @@ def testUpdateV():
for i in range(3):
for j in range(4):
assert_almost_equal(newV[i,j], expectedNewV[i, j])
-
+
+def testMatrixFitNorm():
+ A = np.array([[0.1, 0.1, 0.1],
+ [0.1, 0.1, 0.1],
+ [0.1, 0.1, 0.1],
+ [0.1, 0.1, 0.1],
+ [0.1, 0.1, 0.1],
+ [0.1, 0.1, 0.1]])
+ V = np.array([[0.1, 0.1, 0.1, 0.1],
+ [0.1, 0.1, 0.1, 0.1],
+ [0.1, 0.1, 0.1, 0.1]])
+ D = coo_matrix((ones(6),([0, 1, 2, 3, 4, 5], [0, 1, 1, 2, 3, 3])), shape=(6, 4), dtype=np.uint8).tocsr()
+ DrowNum, DcolNum = D.shape
+ expectedNorm = norm(D - dot(A,V))**2
+ fit = 0
+ for i in xrange(DrowNum):
+ for j in xrange(DcolNum):
+ fit += matrixFitNormElement(i, j, D, A, V)
+ assert_almost_equal(fit, expectedNorm)
+
View
@@ -7,7 +7,7 @@
import numpy as np
import os
import fnmatch
-from commonFunctions import squareFrobeniusNormOfSparse
+from commonFunctions import squareFrobeniusNormOfSparse, fitNorm
__version__ = "0.1"
@@ -19,14 +19,6 @@
__DEF_LMBDA = 0
__DEF_EXACT_FIT = False
-
-def fitNorm(row, col, Xi, ARk, A):
- """
- Computes i,j element of the squared Frobenius norm of the fitting matrix
- """
- ARAtValue = dot(ARk[row,:], A[col,:])
- return (Xi[row, col] - ARAtValue)**2
-
def rescal(X, rank, **kwargs):
"""
RESCAL

0 comments on commit f1d48dc

Please sign in to comment.