def Sources(t ,w1, ptot,ptot1=.2,  dynamic=2, n=2, J=3, Opt=1 , w2=1):
    '''
    Creation of the sources, exactly sparse in DCT. 
    Output: a n*t matrix, sparse in DCT.
    '''    
    if Opt==1:
        Sw=np.zeros((n, t, J+1))
        for l in range(J):
            S=np.zeros((n,t))  
            
            X,X0,A0,S,N,sigma_noise,kern=bssJ.Make_Experiment_Coherent(t_samp=t,ptot=ptot,w=w1,dynamic=dynamic)
            Sw[:,:, l]=dp(S)
            
        X,X0,A0,S,N,sigma_noise,kern=bssJ.Make_Experiment_Coherent(t_samp=t,ptot=ptot1,w=w2,dynamic=dynamic)
        Sw[:,:,-1]=dp(S)
        Su=ps.backward1d(Sw)
        
    else:
        Sw=np.zeros((n, t, J+1))
        for l in range(J):
            S=np.zeros((n,t))  
            
            X,X0,A0,S,N,sigma_noise,kern=bssJ.Make_Experiment_Coherent(t_samp=t,ptot=ptot,w=w1,dynamic=dynamic)
            Sw[:,:, l]=dp(S)
        Su=ps.backward1d(Sw)
        
    return Su
def amcaps(X, dS , dPatch, aMCA, Init):
    n=dS['n']
    t=dS['t']
    
    J=dPatch['J']
    Sps=np.zeros((n, t, J+1))
    Xw = ps.forward1d(X,J=J)
    n_Xw = np.shape(Xw)
    Xmca = Xw[:,:,0:J].reshape(n_Xw[0],n_Xw[1]*J)
    
    dSp=dp(dS)
    dSp['t']=t*J

    (A,temp)=AMCA(Xmca, dSp, aMCA=aMCA,Init=Init)  
    
    
    Sps[:,:,:-1]=temp.reshape(n, t, J)
    
    Ra = np.dot(A.T,A)  
    Ua,Sa,Va = np.linalg.svd(Ra)
    iRa = np.dot(Va.T,np.dot(np.diag(1./Sa),Ua.T))
    piA = np.dot(iRa,A.T)    
    Sps[:,:,-1] = np.dot(piA,Xw[:,:,-1])
    
    Sf=ps.backward1d(Sps)
    
    return (A,Sf)
Beispiel #3
0
def GMCA_star_V2(Xin, J_2D, rank):
    '''X dee taillee (m, N, N)'''

    m = np.shape(Xin)[0]
    N = np.shape(Xin)[1]
    mw = ps.forward(Xin.reshape((m, N, N)), J=J_2D)
    X = mw[:, :, :, :J_2D].reshape(m, J_2D * N**2)

    dS = {}
    dS['n'] = rank
    dS['m'] = m
    dS['t'] = N**2
    dS['kSMax'] = 3
    dS['iteMaxXMCA'] = 400
    A, S = amca.AMCA(X, dS, 0, 1)

    SFinW = np.zeros((rank, N**2, J_2D + 1))
    SFinW[:, :, 0:J_2D] = S.reshape(rank, N**2, J_2D)

    SFinW[:, :, J_2D] = np.dot(np.linalg.pinv(A), mw[:, :, :,
                                                     J_2D].reshape(m, N**2))

    Sb = ps.backward1d(SFinW)
    #
    Sc = np.reshape(Sb, (rank, N, N))
    return (A, Sc)
def GMCA_patch(kend, mw, Xx, Xy, rank):
    import AMCA_Direct as amca

    J_2D = np.shape(mw)[-1] - 1
    nb_obs = np.shape(mw)[0]
    N = Xx[1] - Xx[0]
    Xp = mw[:, Xx[0]:Xx[1], Xy[0]:Xy[1], :]
    X1 = Xp[:, :, :, :J_2D].reshape(nb_obs, (J_2D) * N**2)
    dS = {}

    dS['n'] = rank
    dS['m'] = nb_obs
    dS['t'] = N**2
    dS['kSMax'] = kend
    dS['iteMaxXMCA'] = 400
    A, S = amca.AMCA(X1, dS, 0, 1)
    SFinW = np.zeros((rank, N**2, J_2D + 1))
    SFinW[:, :, 0:J_2D] = S.reshape(rank, N**2, J_2D)

    SFinW[:, :, J_2D] = np.dot(np.linalg.pinv(A),
                               Xp[:, :, :, J_2D].reshape(nb_obs, N**2))

    Sb = ps.backward1d(SFinW)

    Sc = np.reshape(Sb, (rank, N, N))

    return (A, Sc)
def Threshold_1D(X,W=None,J=2,lam=0.1,optCoarse=1):
   
    """
    
    Code that performs signal thresholding in the 1D isotropic undecimated wavelets
    
    Inputs:
    
        X : Input data (m x n_samp)
        W   : weights (m x n_coef)
        J : number of scales
        lam : threshold
        optCoarse : if 0, set the coarse scale coefficients to 0
    Output: 
        X_thrd : Output data (m x n_samp)
        
    """
    
    CardS=None
    
    nS = np.shape(X)
    n = nS[0]
    t = np.int(nS[1])
    
    Wt_c = pys.forward1d(X,J = J)      
    S = Wt_c[:,:,0:J].reshape(n,J*t)
      
    for r in range(n):
        
        if W == None:
            
            if CardS is not None:
                Kval = np.int(CardS[r])
                I = np.argsort(abs(S[r,:]))[::-1]
                th = abs(S[r,I[Kval]])
            else:
                th = lam
                
                
            S[r,:] = (S[r,:] - th*np.sign(S[r,:]))*(abs(S[r,:]) - th > 0)
            
            
        else:
            S[r,:] = (S[r,:] - lam*W[r,:]*np.sign(S[r,:]))*(abs(S[r,:]) - lam*W[r,:] > 0)
                

    Wt_c[:,:,0:J] = S.reshape(n,t,J)

    if optCoarse == 0:
        Wt_c[:,:,J] = np.zeros(np.shape(Wt_c[:,:,J])) 

        
    rec = pys.backward1d(Wt_c) 
    
    
    
    return rec
Beispiel #6
0
def seuillage_star(Sini, diffi, K, res, t, eps=1e-3):
    Si = dp(Sini)
    diff = dp(diffi)
    S_ = ps.forward1d(Si.reshape(1, t), J=res)
    grad_ = ps.forward1d(diff.reshape(1, t), J=res)
    ww = np.zeros((t))
    for j in range(res):
        thr = K * mad(grad_[0, :, j])
        valmax = np.max(abs(S_[0, :, j]))
        ww = eps / (eps + abs(S_[0, :, j]) / valmax)
        S_[0, :, j] = softThres(S_[0, :, j], thr * ww)

    S_ret = ps.backward1d(S_.reshape(1, t, res + 1))[0, :]
    return (S_ret)
def bGMCA_MainBlock_NMF_ondt_naif(X=0,
                                  n=0,
                                  A=0,
                                  S=0,
                                  kend=3,
                                  nmax=100,
                                  L0=0,
                                  verb=0,
                                  blocksize=2,
                                  tol=1e-12,
                                  optBlock=0,
                                  J=2):
    '''Usage:
        S,A,exception = bGMCA_MainBlock_NMF_ondt_naif(X=0,n=0,A=0,S=0,kend=3,nmax=100,L0=0,verb=0,blocksize=2,tol=1e-12,optBlock=0,J=0)
    
    
      Inputs:
       X    : m x t array (input data, each row corresponds to a single observation)
       n     : scalar (number of sources to be estimated)
       A    : m x n array (initialization of the mixing matrix - can be performed by the bGMCA function)
       S    : n x t array (initialization of the sources - can be performed by the bGMCA function)
       kend : scalar (final value of the k-mad thresholding)
       nmax  : scalar (number of iterations)
       L0   : boolean (0: use of the L1 norm, 1: use of the L0 norm) 
       verb   : boolean (if set to 1, in verbose mode)
       blocksize : int (size of the blocks)
       tol : float (stopping criterion)
       optBlock: int in {0,1,2,3} (way the block is constructed: 0 : Random creation of the block, 1 : Correlation, 2 : Loop over all the sources + take the sources that are the most correlated with the current one, 3 : We create the batchs sequentially)
       J : int (number of wavelet scales. If J = 0, no wavelet transform)
    
      Outputs:
       S    : n x t array (estimated sources)
       A    : m x n array (estimated mixing matrix)
       exception : boolean (equals to 1 is a SVD did not converge during the iterations)
    
      Description:
        Computes the sources and the mixing matrix with bGMCA using blocks. Enforces non-negativity in the direct domain and sparsity in the wavelet domain. Does not perform the initialization of A and S
    
      Example:
         S,A,exception = bGMCA_MainBlock_NMF_ondt_naif(X,n=50,A,S,kend=3,nmax=10000,L0=0,verb=1,blocksize=5,tol=1e-12,optBlock=0,J=2)'''

    Xdir = cp.deepcopy(X)
    t = np.shape(Xdir)[1]
    Xw = pys.forward1d(X, J=J)
    n_Xw = np.shape(Xw)
    X = Xw[:, :, 0:J].reshape(n_Xw[0], n_Xw[1] * J)

    #--- Initialization
    optPos = 1
    powCor = 0.5
    n_S = np.shape(S)
    exception = 0

    perc = 1. / nmax

    thrdTab = np.zeros((nmax + 1, n_S[0]))

    tabCard = -np.ones((n, 1))

    if optPos in [1, 2, 3]:
        for ii in range(
                0, n_S[0]
        ):  # Initialization to ensure that the given matrices A and S are non negative
            Sl = S[ii, :]
            Al = A[:, ii]

            if optPos in [1, 2]:
                indMax = np.argmax(abs(Sl))
                if Sl[indMax] < 0:
                    Sl = -Sl
                    Al = -Al

                Sl[Sl < 0] = 0
                if optPos == 1:
                    Al[Al < 0] = 0

                    Al = Al / np.linalg.norm(Al)

            elif optPos == 3:
                indMax = np.argmax(abs(Al))
                if Al[indMax] < 0:
                    Sl = -Sl
                    Al = -Al

                Al[Al < 0] = 0

                Al = Al / (1e-24 + np.linalg.norm(Al))

            S[ii, :] = Sl
            A[:, ii] = Al

    # Stopping/iteration variables

    Go_On = 1
    it = 1

    if verb:
        print("Starting main loop ...")
        print(" ")
        print("  - Final k: ", kend)
        print("  - Maximum number of iterations: ", nmax)
        print("  - Batch size: ", blocksize)
        print("  - Using support-based threshold estimation")
        if L0:
            print("  - Using L0 norm rather than L1")
        print(" ")
        print(" ... processing ...")
        start_time = time.time()

    # Defines the residual

    Resi = cp.deepcopy(X)

    #---
    #--- Main loop
    #---

    while Go_On:
        it += 1

        if it == nmax:
            Go_On = 0

        #--- Estimate the sources (only when the corresponding column is non-zeros)

        sigA = np.sqrt(np.sum(A * A, axis=0))
        indS = np.where(sigA > 1e-24)[0]

        if optBlock == 0:  # Random
            if blocksize < n_S[0]:
                IndBatch = randperm(
                    len(indS))  #---- mini-batch amongst available sources
            else:
                IndBatch = range(len(indS))

            if blocksize < len(indS):
                indS = indS[IndBatch[0:blocksize]]

        elif optBlock == 1:  # Correlation
            if blocksize < n_S[0]:
                currSrcInd = it % len(indS)
                currSrcInd = indS[currSrcInd]
                currSrc = np.power(S[currSrcInd, :].T, powCor)
                matCor = np.dot(np.power(S, powCor), currSrc)
                matCor[currSrcInd] = -1
                IndBatch = np.argsort(matCor)
                IndBatch = np.append(IndBatch, currSrcInd)
                IndBatch = IndBatch[::-1]

            else:
                IndBatch = range(len(indS))

            if blocksize < len(indS):
                if len(indS) == n_S[0]:
                    indS = indS[IndBatch[0:blocksize]]

                else:
                    print('Attention, cas special')

                    indSTemp = [currSrcInd]
                    ii = 0
                    while len(indSTemp) < blocksize:
                        ii = ii + 1
                        if IndBatch[ii] in indS:
                            indSTemp = indSTemp + [IndBatch[ii]]

        elif optBlock == 2:  # Loop over all the sources + take the sources that are the most correlated with the current one
            if blocksize < n_S[0]:
                currSrcInd = it % len(indS)
                currSrcInd = indS[currSrcInd]
                angTab = np.dot(A[:, currSrcInd].T, A)
                angTab[
                    currSrcInd] = -2  #0 : correspond a l'angle le plus grand, 90 degres
                IndBatch = np.argsort(angTab)
                IndBatch = np.append(IndBatch, currSrcInd)
                IndBatch = IndBatch[::-1]

            else:
                IndBatch = range(len(indS))

            if blocksize < len(indS):
                if len(indS) == n_S[0]:
                    indS = indS[IndBatch[0:blocksize]]
                else:
                    print('Attention, cas special')
                    indSTemp = [currSrcInd]
                    ii = 0
                    while len(indSTemp) < blocksize:
                        ii = ii + 1
                        if IndBatch[ii] in indS:
                            indSTemp = indSTemp + [IndBatch[ii]]

        elif optBlock == 4:  # We create the batchs sequentially
            indStt = blocksize * (it - 1) % np.shape(S)[0]
            indEnd = blocksize * it % np.shape(S)[0]

            if indStt < indEnd:
                IndBatch = range(int(indStt), int(indEnd))
            else:
                ind1 = range(indStt, np.shape(S)[0])
                if (indEnd > 0):
                    ind2 = range(0, indEnd)
                    IndBatch = np.concatenate((ind1, ind2))
                else:
                    IndBatch = ind1

            if blocksize < len(indS):
                if len(indS) == n_S[0]:
                    indS = indS[IndBatch[0:blocksize]]

                else:
                    print('Attention, cas special')
                    indSTemp = [indStt]
                    ii = 0
                    while len(indSTemp) < blocksize:
                        ii = ii + 1
                        if IndBatch[ii] in indS:
                            indSTemp = indSTemp + [IndBatch[ii]]

        Resi = Resi + np.dot(A[:, indS],
                             S[indS, :])  # Putting back the sources

        if np.size(indS) > 0:

            if len(indS) > 1:

                # Least_square estimate

                Ra = np.dot(A[:, indS].T, A[:, indS])
                excThisIt = 0
                try:
                    Ua, Sa, Va = np.linalg.svd(Ra)
                except np.linalg.linalg.LinAlgError:
                    print(indS)
                    print(np.sum(np.isnan(Ra)))
                    print(np.sum(np.isinf(Ra)))
                    print('SVD DID NOT CONVERGE')
                    exception += 1
                    excThisIt = 1

                if excThisIt == 0:
                    cd_Ra = np.min(Sa) / np.max(Sa)
                else:
                    cd_Ra = np.linalg.norm(Ra, ord=-2) / np.linalg.norm(Ra,
                                                                        ord=2)

                if (cd_Ra > 1e-12) and not (
                        excThisIt):  # if the condition number is large enough
                    iRa = np.dot(Va.T, np.dot(np.diag(1. / Sa), Ua.T))
                    piA = np.dot(iRa, A[:, indS].T)
                    piA = np.real(piA)
                    S[indS, :] = np.dot(piA, Resi)

                if (cd_Ra < 1e-12 or excThisIt
                        == 1):  # otherwise a few gradient descent steps
                    print('GRADIENT STEP')
                    if excThisIt == 0:
                        La = np.max(Sa)
                    else:
                        La = np.linalg.norm(Ra, ord=2)
                        print('SVD DID NOT CONVERGE')

                    for it_A in range(0, 10):
                        S[indS, :] = S[indS, :] + 1 / La * np.dot(
                            A[:, indS].T, X - np.dot(A[:, indS], S[indS, :]))

            else:  # only a single element in the selection / the update is straightforward

                S[indS[0], :] = np.dot(
                    1. / np.linalg.norm(A[:, indS[0]]) * A[:, indS[0]], Resi)

            # Non-negativity
            if optPos in [
                    1, 2
            ]:  # If the non-negativity is enforced on the sources
                StempMat = np.zeros((len(indS), t, J + 1))
                StempMat[:, :, 0:J] = S[indS, :].reshape(len(indS), t, J)
                StempMat[:, :, J] = np.dot(np.linalg.pinv(A),
                                           Xw[:, :,
                                              J])[indS, :]  # coarse scale
                StempDir = pys.backward1d(
                    StempMat)  # Go back to the direct domain
                StempDir[
                    StempDir < 0] = 0  # Projection on the positive orthant
                StempMat = pys.forward1d(
                    StempDir, J=J)  # Go again the the wavelet domain
                S[indS, :] = StempMat[:, :, 0:J].reshape(len(indS), J * t)

            Stemp = S[indS, :]

            # Thresholding
            for r in range(len(indS)):
                St = Stemp[r, :]

                #Computation of the effective support
                indNZ = np.where(abs(St) > kend * mad(St))[0]
                thrd = mad(St[indNZ])

                # Computation of the threshold
                Kval = np.min([
                    np.floor(np.max([0.01, perc * it]) * len(indNZ)),
                    n_S[1] - 1.
                ])  # Includes an increasing percentage of available entries
                I = abs(St[indNZ]).argsort()[::-1]
                Kval = np.int(np.min([np.max([Kval, n]), len(I) - 1.]))
                tabCard[indS[r]] = Kval
                IndIX = np.int(indNZ[I[Kval]])
                thrd = abs(St[IndIX])

                thrdTab[it, indS[r]] = thrd

                St[(abs(St) < thrd)] = 0
                indNZ = np.where(abs(St) > thrd)[0]

                if L0 == 0:
                    St[indNZ] = St[indNZ] - thrd * np.sign(St[indNZ])

            S[indS, :] = Stemp

            # --- Updating the mixing matrix
            if len(indS) > 1:

                Atemp = unmix_cgsolve(S[indS, :].T, Resi.T,
                                      maxiter=n)  #---- Using CG
                A[:, indS] = Atemp.T

                if optPos in [1, 3]:  # Enforcing non-negativity on A
                    for ii in range(len(indS)):
                        Al = A[:, indS[ii]]
                        Al[Al < 0] = 0
                        A[:, indS[ii]] = Al

                A[:, indS] = np.dot(
                    A[:, indS],
                    np.diag(1. /
                            (1e-24 + np.sqrt(np.sum(A[:, indS]**2, axis=0))))
                )  #--- Renormalization

            else:  # Case where the update is explicit

                Atemp = np.dot(Resi, S[indS, :].T)
                A[:, indS] = Atemp / (1e-24 + np.linalg.norm(Atemp))

            Resi = Resi - np.dot(A[:, indS],
                                 S[indS, :])  #--- Removing the sources

            if (np.mod(it, 500) == 1) & (verb == 1):
                print("It #", it)
                if len(indS) == 1:
                    print("Deflation")
                elif len(indS) == n:
                    print("GMCA")
                else:
                    print("minibatch - ratio : ", len(indS) / n)

    if verb:
        elapsed_time = time.time() - start_time
        print("Stopped after ", it, " iterations, in ", elapsed_time,
              " seconds")

    SFinW = np.zeros((n, t, J + 1))
    SFinW[:, :, 0:J] = S.reshape(n, t, J)
    SFinW[:, :, J] = np.dot(np.linalg.pinv(A), Xw[:, :, J])
    S = pys.backward1d(SFinW)

    return S, A, exception
def PALM_NMF_MainBlock(X=0,
                       n=0,
                       A=0,
                       S=0,
                       kend=3,
                       nmax=100,
                       L0=0,
                       blocksize=2,
                       tol=1e-12,
                       optPos=0,
                       J=0):
    '''Usage:
        S,A = PALM_NMF_MainBlock(X=0,n=0,A=0,S=0,kend=3,nmax=100,L0=0,blocksize=2,tol=1e-12,optPos = 0,J=0)
        
    
      Inputs:
       X    : m x t array (input data, each row corresponds to a single observation)
       n     : scalar (number of sources to be estimated)
       A    : m x n array (initialization of the mixing matrix - can be performed by the bGMCA function)
       S    : n x t array (initialization of the sources - can be performed by the bGMCA function)
       kend : scalar (final value of the k-mad thresholding)
       nmax  : scalar (number of iterations)
       L0   : boolean (0: use of the L1 norm, 1: use of the L0 norm) 
       blocksize : int (size of the blocks)
       tol : float (stopping criterion)
       optPos : int in {0,1,2,3} option for the non-negativity: 0 no constraint, 1 : non-negativity on A and S, 2: non-negativity on S, 3: non-negativity on A
       J : int (number of wavelet scales. If J = 0, no wavelet transform)
    
      Outputs:
       S    : n x t array (estimated sources)
       A    : m x n array (estimated mixing matrix)
       
      Description:
        Computes the sources and the mixing matrix with a PALM algorithm using blocks. Allows to enforce the non-negativity in the direct domain but not to use sparsity in the wavelet domain at the same time. Does not perform the initialization of A and S
    
      Example:
        S,A = PALM_NMF_MainBlock(X,n=50,A,S,kend=3,nmax=100000,L0=0,blocksize=10,tol=1e-12,optPos = 0,J=0)'''

    # Stopping/iteration variables
    #optPos : 1 : tout, 2 : S, 3 : A

    if J > 0:  # Wavelet transform
        t = np.shape(X)[1]
        Xw = pys.forward1d(X, J=J)
        n_Xw = np.shape(Xw)
        X = Xw[:, :, 0:J].reshape(n_Xw[0], n_Xw[1] * J)

    # Initializations
    Go_On = 1
    it = 1
    Aold = deepcopy(A)
    deltaTabAngle = np.zeros(nmax + 1)
    n_X = np.shape(X)
    thrdTab = -np.ones((n, n_X[1]))

    # Initialization to ensure that the given matrices A and S are non negative
    n_S = np.shape(S)
    for ii in range(0, n_S[0]):
        Sl = S[ii, :]
        Al = A[:, ii]

        if optPos in [1, 2]:
            indMax = np.argmax(abs(Sl))
            if Sl[indMax] < 0:
                Sl = -Sl
                Al = -Al

            Sl[Sl < 0] = 0
            if optPos == 1:
                Al[Al < 0] = 0

                if np.linalg.norm(Al) > 1:
                    Al = Al / np.linalg.norm(Al)

        elif optPos == 3:
            indMax = np.argmax(abs(Al))
            if Al[indMax] < 0:
                Sl = -Sl
                Al = -Al

            Al[Al < 0] = 0
            if np.linalg.norm(Al) > 1:
                Al = Al / np.linalg.norm(Al)

        S[ii, :] = Sl
        A[:, ii] = Al

    #---
    #--- Main loop
    #---

    while Go_On:

        it += 1

        if it == nmax:  # If stopping criterion met
            Go_On = 0

        # We create the blocks deterministically
        indStt = blocksize * (it - 1) % np.shape(S)[0]
        indEnd = blocksize * it % np.shape(S)[0]

        if indStt < indEnd:
            indS = range(int(indStt), int(indEnd))
        else:
            ind1 = range(indStt, np.shape(S)[0])
            if (indEnd > 0):
                ind2 = range(0, indEnd)
                indS = np.concatenate((ind1, ind2))
            else:
                indS = ind1

        if np.size(indS) > 0:

            # Computation of a gradient step for S
            Stemp = S[indS, :].copy()
            Atemp = A[:, indS].copy()

            specNormAtemp = np.linalg.norm(np.dot(Atemp.T, Atemp), ord=2)

            deltaF = np.dot(Atemp.T, np.dot(A, S) - X)
            Stemp = Stemp - 1 / specNormAtemp * deltaF

            # Thresholding
            for r in range(0, np.shape(Stemp)[0]):

                gradSt = Stemp[r, :]

                if thrdTab[
                        indS[r],
                        0] < 0:  # We fix the threshold at the first iteration and keep the same for the following ones.
                    thrd = mad(
                        gradSt
                    )  # We have a single value for the threshold per line
                    thrd = kend * thrd

                    thrd = thrd * np.ones((1, len(gradSt)))[0, :]
                    thrdTab[indS[r], :] = thrd

                thrd = thrdTab[indS[r], :] / specNormAtemp

                if optPos in [
                        1, 2
                ]:  # if the non-negativity is enforced on the sources
                    gradSt[gradSt < thrd] = 0
                    indNZ = np.where(gradSt > thrd)[0]

                    if L0 == 0:
                        gradSt[indNZ] = gradSt[indNZ] - thrd[indNZ] * np.sign(
                            gradSt[indNZ]
                        )  # We only have the positive part => we don't need to use the sign

                else:
                    gradSt[(abs(gradSt) < thrd)] = 0
                    indNZ = np.where(abs(gradSt) > thrd)[0]

                    if L0 == 0:
                        gradSt[indNZ] = gradSt[indNZ] - thrd[indNZ] * np.sign(
                            gradSt[indNZ])

                Stemp[r, :] = gradSt.copy()

            A[:, indS] = Atemp.copy()
            S[indS, :] = Stemp.copy()

            # Computation of the gradient step for A

            Stemp = S[indS, :].copy()
            Atemp = A[:, indS].copy()

            specNormStemp = np.linalg.norm(np.dot(Stemp, Stemp.T), ord=2)
            Atemp = Atemp - 1 / specNormStemp * np.dot(
                (np.dot(A, S) - X), Stemp.T)

            if optPos in [
                    1, 3
            ]:  # If non-negativity is enforced on the mixing matrix
                for r in range(
                        0, Atemp.shape[1]
                ):  # Le fait de multiplier par D ne change rien, vu que ses coeffs sont positifs.
                    Ac = Atemp[:, r]
                    indMax = np.argmax(abs(Ac))
                    if Ac[indMax] < 0:
                        print('Warning, max < 0')
                    Ac[Ac < 0] = 0
                    Atemp[:, r] = Ac

            # Projection of the column of gradA on the L1 ball

            for r in range(0, Atemp.shape[1]):
                if (np.linalg.norm(Atemp[:, r]) > 1):
                    Atemp[:, r] = Atemp[:, r] / np.linalg.norm(
                        Atemp[:, r])  # Normalisation validee

            A[:, indS] = Atemp.copy()
            S[indS, :] = Stemp.copy()

            # Computation of the stopping criterion
            DeltaAngle = np.sum(A * Aold, axis=0)
            deltaTabAngle[it] = np.min(
                DeltaAngle
            )  # min car cos decroissant: on veut que le plus grand angle soit faible, donc le plus petit cos grand
            if np.mod(it, 500) == 0:
                print(it)
                Delta = np.linalg.norm(A - Aold) / (1e-24 +
                                                    np.linalg.norm(Aold))
                print('Delta angle: %s' % (np.arccos(deltaTabAngle[it])))
                print('Delta: %s' % (Delta))

            if it > 10000 and deltaTabAngle[it] > np.cos(9 * 1e-8):
                Go_On = 0

            Aold = deepcopy(A)

    if J > 0:  # Giong back into the direct domain
        SFinW = np.zeros((n, t, J + 1))
        SFinW[:, :, 0:J] = S.reshape(n, t, J)
        SFinW[:, :, J] = np.dot(np.linalg.pinv(A), Xw[:, :, J])
        S = pys.backward1d(SFinW)

    return S, A
def bGMCA_MainBlock(X=0,
                    n=0,
                    A=0,
                    S=0,
                    kend=3,
                    nmax=100,
                    L0=1,
                    verb=0,
                    blocksize=2,
                    tol=1e-12,
                    optBlock=0,
                    J=0,
                    optPos=0):
    '''Usage:
        S,A,exception,Sw = bGMCA_MainBlock(X=0,n=0,A=0,S=0,kend=3,nmax=100,L0=1,verb=0,blocksize=2,tol=1e-12,optBlock=0,J=0,optPos = 0)
        
    
      Inputs:
       X    : m x t array (input data, each row corresponds to a single observation)
       n     : scalar (number of sources to be estimated)
       A    : m x n array (initialization of the mixing matrix)
       S    : n x t array (initialization of the sources)
       kend : scalar (final value of the k-mad thresholding)
       nmax  : scalar (number of iterations)
       L0   : boolean (0: use of the L1 norm, 1: use of the L0 norm) 
       verb   : boolean (if set to 1, in verbose mode)
       blocksize : int (size of the blocks)
       tol : float (stopping criterion)
       optBlock: int in {0,1,2,3} (way the block is constructed: 0 : Random creation of the block, 1 : Correlation, 2 : Loop over all the sources + take the sources that are the most correlated with the current one, 3 : We create the blocks sequentially)
       J : int (number of wavelet scales. If J = 0, no wavelet transform)
       optPos : int in {0,1,2,3} option for the non-negativity: 0 no constraint, 1 : non-negativity on A and S, 2: non-negativity on S, 3: non-negativity on A
    
      Outputs:
       S    : n x t array (estimated sources)
       A    : m x n array (estimated mixing matrix)
       exception : boolean (equals to 1 is a SVD did not converge during the iterations)
       Sw : n x (t x j) array (wavelet transform of the sources)
       
      Description:
        Computes the sources and the mixing matrix with bGMCA using blocks. Does not perform the initialization of A and S
    
      Example:
        S,A,exception,Sw = bGMCA_MainBlock(Xw,50,A,S,kend = 3,nmax=10000,L0=0,verb=1,blocksize=10,optBlock=0,J=2,optPos=0)'''

    if J > 0:  # Use of wavelets
        Xdir = cp.deepcopy(X)
        t = np.shape(Xdir)[1]
        Xw = pys.forward1d(X, J=J)
        n_Xw = np.shape(Xw)
        X = Xw[:, :, 0:J].reshape(n_Xw[0], n_Xw[1] * J)

    #--- Initialization

    powCor = 0.5
    n_S = np.shape(S)
    exception = 0
    comptPasGrad = 0

    perc = 1. / nmax

    Aold = deepcopy(A)

    deltaTabAngle = np.zeros(nmax + 1)

    if optPos in [1, 2, 3]:
        for ii in range(
                0, n_S[0]
        ):  # Initialization to ensure that the given matrices A and S are non negative
            Sl = S[ii, :]
            Al = A[:, ii]

            if optPos in [1, 2]:
                indMax = np.argmax(abs(Sl))
                if Sl[indMax] < 0:
                    Sl = -Sl
                    Al = -Al

                Sl[Sl < 0] = 0
                if optPos == 1:
                    Al[Al < 0] = 0

                    Al = Al / np.linalg.norm(Al)

            elif optPos == 3:
                indMax = np.argmax(abs(Al))
                if Al[indMax] < 0:
                    Sl = -Sl
                    Al = -Al

                Al[Al < 0] = 0

                Al = Al / (1e-24 + np.linalg.norm(Al))

            S[ii, :] = Sl
            A[:, ii] = Al

    # Stopping/iteration variables

    Go_On = 1
    it = 1

    if verb:
        print("Starting main loop ...")
        print(" ")
        print("  - Final k: ", kend)
        print("  - Maximum number of iterations: ", nmax)
        print("  - Batch size: ", blocksize)
        print("  - Using support-based threshold estimation")
        if L0:
            print("  - Using L0 norm rather than L1")
        print(" ")
        print(" ... processing ...")
        start_time = time.time()

    # Defines the residual

    Resi = cp.deepcopy(X)

    #---
    #--- Main loop
    #---

    while Go_On:
        it += 1

        if it == nmax:
            Go_On = 0

        #--- Estimate the sources (only when the corresponding column is non-zeros)

        sigA = np.sqrt(np.sum(A * A, axis=0))
        indS = np.where(sigA > 1e-24)[0]

        if optBlock == 0:  # Random creation of the block
            if blocksize < n_S[0]:
                IndBatch = randperm(
                    len(indS))  #---- mini-batch amongst available sources
            else:
                IndBatch = range(len(indS))

            if blocksize < len(indS):
                indS = indS[IndBatch[0:blocksize]]

        elif optBlock == 1:  # Correlation
            if blocksize < n_S[0]:
                currSrcInd = it % len(indS)
                currSrcInd = indS[currSrcInd]
                currSrc = np.power(S[currSrcInd, :].T, powCor)
                matCor = np.dot(np.power(S, powCor), currSrc)
                matCor[currSrcInd] = -1
                IndBatch = np.argsort(matCor)
                IndBatch = np.append(IndBatch, currSrcInd)
                IndBatch = IndBatch[::-1]

            else:
                IndBatch = range(len(indS))

            if blocksize < len(indS):
                if len(indS) == n_S[0]:
                    indS = indS[IndBatch[0:blocksize]]

                else:
                    print('Attention, cas special')

                    indSTemp = [currSrcInd]
                    ii = 0
                    while len(indSTemp) < blocksize:
                        ii = ii + 1
                        if IndBatch[ii] in indS:
                            indSTemp = indSTemp + [IndBatch[ii]]

        elif optBlock == 2:  # Loop over all the sources + take the sources that are the most correlated with the current one
            if blocksize < n_S[0]:
                currSrcInd = it % len(indS)
                currSrcInd = indS[currSrcInd]
                angTab = np.dot(A[:, currSrcInd].T, A)
                angTab[
                    currSrcInd] = -2  #0 : correspond a l'angle le plus grand, 90 degres
                IndBatch = np.argsort(angTab)
                IndBatch = np.append(IndBatch, currSrcInd)
                IndBatch = IndBatch[::-1]

            else:
                IndBatch = range(len(indS))

            if blocksize < len(indS):
                if len(indS) == n_S[0]:
                    indS = indS[IndBatch[0:blocksize]]
                else:
                    print('Attention, cas special')
                    indSTemp = [currSrcInd]
                    ii = 0
                    while len(indSTemp) < blocksize:
                        ii = ii + 1
                        if IndBatch[ii] in indS:
                            indSTemp = indSTemp + [IndBatch[ii]]

        elif optBlock == 3:  # We create the batchs deterministically
            indStt = blocksize * (it - 1) % np.shape(S)[0]
            indEnd = blocksize * it % np.shape(S)[0]

            if indStt < indEnd:
                IndBatch = range(int(indStt), int(indEnd))
            else:
                ind1 = range(indStt, np.shape(S)[0])
                if (indEnd > 0):
                    ind2 = range(0, indEnd)
                    IndBatch = np.concatenate((ind1, ind2))
                else:
                    IndBatch = ind1

            if blocksize < len(indS):
                if len(indS) == n_S[0]:
                    indS = indS[IndBatch[0:blocksize]]

                else:
                    print('Attention, cas special')
                    indSTemp = [indStt]
                    ii = 0
                    while len(indSTemp) < blocksize:
                        ii = ii + 1
                        if IndBatch[ii] in indS:
                            indSTemp = indSTemp + [IndBatch[ii]]

        Resi = Resi + np.dot(A[:, indS],
                             S[indS, :])  # Putting back the sources

        if np.size(indS) > 0:

            if len(indS) > 1:

                # Least_square estimate

                Ra = np.dot(A[:, indS].T, A[:, indS])
                excThisIt = 0
                try:
                    Ua, Sa, Va = np.linalg.svd(Ra)
                except np.linalg.linalg.LinAlgError:
                    print(indS)
                    print(np.sum(np.isnan(Ra)))
                    print(np.sum(np.isinf(Ra)))
                    print('ATTENTION PAS DE CONVERGENCE DE LA SVD')
                    exception += 1
                    excThisIt = 1

                if excThisIt == 0:
                    cd_Ra = np.min(Sa) / np.max(Sa)
                else:
                    cd_Ra = np.linalg.norm(Sa, ord=-2) / np.linalg.norm(Sa,
                                                                        ord=2)

                if (cd_Ra > 1e-12) and not (
                        excThisIt):  # if the condition number is large enough
                    iRa = np.dot(Va.T, np.dot(np.diag(1. / Sa), Ua.T))
                    piA = np.dot(iRa, A[:, indS].T)
                    S[indS, :] = np.dot(piA, Resi)

                if (cd_Ra < 1e-12 or excThisIt
                        == 1):  # otherwise a few gradient descent steps
                    comptPasGrad += 1
                    print('GRADIENT STEP INSTEAD OF PSEUDO-INVERSE NUMBER %s' %
                          comptPasGrad)
                    if excThisIt == 0:
                        La = np.max(Sa)
                    else:
                        La = np.linalg.norm(Ra, ord=2)
                        print('WARNING SVD DID NOT CONVERGE AT THIS ITERATION')

                    for it_A in range(0, 10):
                        S[indS, :] = S[indS, :] + 1 / La * np.dot(
                            A[:, indS].T, X - np.dot(A[:, indS], S[indS, :]))

            else:  # only a single element in the selection / the update is straightforward

                S[indS[0], :] = np.dot(
                    1. / np.linalg.norm(A[:, indS[0]]) * A[:, indS[0]], Resi)

            # Thresholding

            Stemp = S[indS, :]

            for r in range(len(indS)):  # Thresholding
                St = Stemp[r, :]
                indNZ = np.where(abs(St) > kend * mad(St))[0]
                thrd = mad(St[indNZ])

                Kval = np.min([
                    np.floor(np.max([0.01, perc * it]) * len(indNZ)),
                    n_S[1] - 1.
                ])  # Includes an increasing percentage of available entries
                I = abs(St[indNZ]).argsort()[::-1]
                Kval = np.int(np.min([np.max([Kval, n]), len(I) - 1.]))
                IndIX = np.int(indNZ[I[Kval]])
                thrd = abs(St[IndIX])

                if optPos in [1, 2]:
                    St[St < thrd] = 0
                    indNZ = np.where(St > thrd)[0]

                    if L0 == 0:
                        St[indNZ] = St[indNZ] - thrd * np.sign(St[indNZ])

                else:
                    St[(abs(St) < thrd)] = 0
                    indNZ = np.where(abs(St) > thrd)[0]

                    if L0 == 0:
                        St[indNZ] = St[indNZ] - thrd * np.sign(St[indNZ])

            S[indS, :] = Stemp

            # --- Updating the mixing matrix

            if len(indS) > 1:

                Atemp = unmix_cgsolve(S[indS, :].T, Resi.T,
                                      maxiter=n)  #---- Using CG

                A[:, indS] = Atemp.T

                A[:, indS] = np.dot(
                    A[:, indS],
                    np.diag(1. /
                            (1e-24 + np.sqrt(np.sum(A[:, indS]**2, axis=0))))
                )  #--- Renormalization

            else:

                Atemp = np.dot(Resi, S[indS, :].T)
                A[:, indS] = Atemp / (1e-24 + np.linalg.norm(Atemp))

            if optPos in [1, 3]:
                for ii in range(len(indS)):
                    Al = A[:, indS[ii]]
                    Al[Al < 0] = 0
                    A[:, indS[ii]] = Al

            Resi = Resi - np.dot(A[:, indS],
                                 S[indS, :])  #--- Removing the sources

            Delta = np.linalg.norm(A - Aold) / (1e-24 + np.linalg.norm(Aold))

            if (np.mod(it, 500) == 1) & (verb == 1):
                print("It #", it, " - Delta = ", Delta)
                if len(indS) == 1:
                    print("Deflation")
                elif len(indS) == n:
                    print("GMCA")
                else:
                    print("minibatch - ratio : ", len(indS) / n)

            if verb:
                DeltaAngle = np.sum(A * Aold, axis=0)
                deltaTabAngle[it] = np.min(
                    DeltaAngle
                )  # min car cos decroissant: on veut que le plus grand angle soit faible, donc le plus petit cos grand
                if np.mod(it, 500) == 1:
                    print('Delta angle: %s' % (np.arccos(deltaTabAngle[it])))

            Aold = deepcopy(A)

    if verb:
        elapsed_time = time.time() - start_time
        print("Stopped after ", it, " iterations, in ", elapsed_time,
              " seconds")

    if J > 0:
        Sw = cp.deepcopy(S)
        SFinW = np.zeros((n, t, J + 1))
        SFinW[:, :, 0:J] = S.reshape(n, t, J)
        SFinW[:, :, J] = np.dot(np.linalg.pinv(A), Xw[:, :, J])
        S = pys.backward1d(SFinW)

    if J > 0:
        return S, A, exception, Sw
    else:
        return S, A, exception
def GFB_WSparse_Positivity_1D(X,W=None,CardS = None,J=2,lam = 1,niter=250,tol=1e-6,Analysis=False,verb=0,XisOndt=0,coarseScale=0,A=0):
    
    """
    
    Solves : Argmin_(x>=0) lam *||W o (S Phi^T) ||_1 using 1D wavelets
    
    Inputs:
    
        X : Input data (m x n_samp)
        W   : weights (m x n_coef)
        niter : number of iterations
        J : number of scales
        tol : limit on the stopping criterion 
        lam : threshold
        Analysis : if set, rather uses a synthesis prior
        verb : enables verbose mode
        XisOndt: set to 1 if X is already in the wavelet domain
        coarseScale : contains the coarse scale of X if X is already in the wavelet domain
        
    Output: 
        X_thrd : Output data (m x n_samp)
        
        if XisOndt = 1, additional outputs:
        coarseScale : coarse scale of X

    """
    if XisOndt==1:
        n_X = np.shape(X)
        m = n_X[0]
        t = np.shape(coarseScale)[1]
        Wt_c = np.zeros((m,t,J+1))
        Wt_c[:,:,0:J] = X.reshape(m,t,J)
        Wt_c[:,:,J] = np.dot(np.linalg.pinv(A),coarseScale) #coarseScale
        X = pys.backward1d(Wt_c) 

        
    u = dp(X)
    v = dp(X)
    Xout = dp(X)


    Xold= dp(Xout)
    
    w_u = 0.8
    w_v = 0.2
    gamma = 0.9
    mu = 1.5
    
    it = 0
    Go_On = 1
    tk = 1
    
    while Go_On:
        
        it+=1
        
        dG = Xout - X
        
        # Update positivity
        
        Xt = 2.*Xout - u - gamma*dG
        Xt = Xt*(Xt > 0) - Xout
        u = u + mu*Xt
        
        # Update sparsity
        
        Xt = 2.*Xout - v - gamma*dG
        if Analysis:
            Xt = Analysis_prox(Xt,W = W,J=J,lam=lam) - Xout
        else:
            Xt = Threshold_1D(Xt,W=W,J=J,lam=lam,CardS=CardS) - Xout
        v = v + mu*Xt
        
        # Update Sout
        
        tkp = 0.5*(1+np.sqrt(1. + 4.*(tk**2)))
        
        Xt = w_u*u + w_v*v
                
        Xout = Xt + (tk - 1.)/tkp*(Xt - Xold)
        
        diffX = np.sum(abs(Xold - Xout))/(1e-24 + np.sum(abs(Xold)))
        Xold = dp(Xout)
        
        if verb:
            print("It. #",it," - relative variation : " ,diffX)
        
        if diffX < tol:
            Go_On=0
        if it > niter:
            Go_On=0
    
    if XisOndt==1:
        Xout = pys.forward1d(Xout,J = J)  
        coarseScale = Xout[:,:,J]
        Xout = Wt_c[:,:,0:J].reshape(m,J*t)

        return Xout,coarseScale
    
    else:
        
        return Xout