# coding=utf-8
__author__ = 'yinglang'

from numpy import *

dish = array(
        [[0, 0, 0, 2, 2],
        [0, 0, 0, 3, 3],
        [0, 0, 0, 1, 1],
        [1, 1, 1, 0, 0],
        [2, 2, 2, 0, 0],
        [5, 5, 5, 0, 0],
        [1, 1, 1, 0, 0]])
zero = 1e-10

# SVD
def svdTest():
    U, sigma, VT = linalg.svd(dish)

# SVD 反求
def inverseSVD(U,sigma, VT):
    m = U.shape[0]; n = VT.shape[0]
    sigMatrix = zeros((m,n))
    for i in range(min(m,n)):
        sigMatrix[i,i] = sigma[i]
    redish = mat(U) * sigMatrix * VT            # 只要有一个是mat，就会使用矩阵乘法

    redish = array(redish)
    indexes = nonzero(abs(redish) < zero)           # 找到所有小于1e-10的数的下标
    redish[indexes] = 0                         # 将这些数置为 0
    return redish

# SVD 反求二
def inverseSVD2(U, sigma, VT):
    m = U.shape[0]; n = VT.shape[0]
    if m > n:
        # 令U中的前n列数据乘以相应的sigma值，因为numpy.array shape(n,m) * shape(n,1) 等价于 重复相乘 shape(n,m)*shape(n,m),所以要转置
        redish = (U[:, :n].T * array([sigma]).T).T          # = [s1*u1, s2*u2 .. sn*un]; [UA UB] * [S;0] = UA*S = U(:,0:n)*S
                                                            # 每行n以后的部分乘以的是0对计算无影响，直接不计算
        redish = mat(redish) * VT
    else :
        redish = (U.T * array([sigma]).T).T
        redish = mat(redish) * VT[:m, :]                    # = [U*S 0] * [ A B; C D] = [U*S*A U*S*B] = U*S*[A B] = U*S*VT(0:m,:)

    redish = array(redish)
    indexes = nonzero(abs(redish) < zero)           # 找到所有小于1e-10的数的下标
    redish[indexes] = 0                         # 将这些数置为 0
    return redish

import time
def countTime(func, *args):
    start = time.time()
    func(*args)
    end = time.time()
    return end-start

def getData(num=10000, randD=100):
    Us = []
    VTs = []
    sigs = []

    for ch in range(num):
        m = random.randint(1, randD)
        n = random.randint(1, randD)
        matrix0 = random.normal(0, 10, (m, n))
        U, sig, VT = linalg.svd(matrix0)
        Us.append(U)
        sigs.append(sig)
        VTs.append(VT)
    return Us, sigs, VTs

start = time.time()
Us, sigs, VTs = getData()
diposeTime = time.time() - start
print diposeTime

start = time.time()
for ch in range(len(Us)):
    U = Us[ch]; sig = sigs[ch]; VT = VTs[ch]
    matrix1 = inverseSVD(U, sig, VT)
print time.time() - start

start = time.time()
for ch in range(len(Us)):
    U = Us[ch]; sig = sigs[ch]; VT = VTs[ch]
    matrix1 = inverseSVD2(U, sig, VT)
print time.time() - start
