def rAMCA(Xini,A,amca=1): '''Computes the rAMCA algorithm. It estimates A, S and O jointly. It estimates the outliers based on their norm and delta-density, and estimates A and S with AMCA wich penalizes the corrupted samples. Input: Xini: Observations, represented in a domain in which both the sources and the outliers are sparse. A: initializing mixing matrix amca: boolean. If it is set to one, AMCA is performed, otherwise, GMCA is performed in the inner loop to estimate A and S. (Should be one) Output: S: estimated sparse sources A: estimated mixing matrix O: estimated sparse outliers ''' #Initialize the variables and parameters X=copy(Xini) A=copy(A) O=np.zeros(np.shape(Xini)) itMAX=aS['iteMaxrAMCA'] IndexTot=0 convA=10 #stop when A has converged densityMin=WminD[str(dS['n'])]#Maximal value of the delta-density for not being considered as corrupted gammaValue=np.sqrt(2)*scipy.special.gamma((dS['m']+1.)/2.)/scipy.special.gamma((dS['m'])/2.) #For the l_2,1 norm estimation of the outliers perc=5 #percentage of outliers newly considered at every iteration (can be smaller to avoid false estimation of outliers) tperc=perc/100.*dS['t'] suppOest=np.zeros((dS['t'],)) #Support of the estimated outliers new=np.zeros((dS['t'],)) # Newly estimated outliers #First estimation of A and S S,A=AMCA(X-O,A,amca) #Start of the main loop while (IndexTot<itMAX and (np.sum(new)>0 or convA>5)): #Stop if A has converged and no outlier has been estimated ######################################### #Update the support of the outliers ######################################### #Update the delta density of the estimated sources deltaDen=np.linalg.norm(S,axis=0,ord=1.)/np.max(np.abs(S)+1e-6,axis=0) #update the l2 norm of the columns normX=np.linalg.norm(X-A.dot(S)-O,axis=0) if np.sum(deltaDen>densityMin)>0: deltaDen[deltaDen<densityMin]=0 #The sparse samples are not considered normX[deltaDen==0]=0 minSuppX=np.percentile(normX[normX>0],max((np.sum(normX>0)-tperc)/np.sum(normX>0)*100,0)) #Lower value of the norm of the admissible corrupted samples if (np.sum(new)==0 and convA<5): #If it has nearly converged, decreases the value of minSuppX to avoid local minima and bias minSuppX=mad(X-A.dot(S)-O)*gammaValue new=np.array(normX>minSuppX,int) #Support of the samples corresponding to the largest entries in the residue and whose delta-density is large enough new[new*suppOest>0]=0 # Take only the new oultiers# suppOest+=np.array(new,int) #Add the new outliers suppOest[suppOest>0]=1 # support of the outliers# #Sanity Check to avoid the false estimation of outliers. It is not necessary if the initial matrix A has a small condition number (less than 50), and if the parameter perc is small enough. #As the outliers are broadly distributed, its m eigenvalues should be centered around a same value. #If a source has been wrongly estimated as being outliers, then one of the eigenvalue will be much more larger than the other one (the energy of the sources has been added up to the one of the outliers) #If the difference between the largest eigenvalue and the mean of the other eigenvalues is equal to five time the standard deviation of the m-1 smallest eigenvalues, then, # the samples contributing to this eigenvalue are not considered as being outliers. if np.sum(new)>max(0.005*dS['t'],dS['m']) : #if new outliers have been deteced# Onew=(X/(np.linalg.norm(X,axis=0)))[:,(suppOest>0)] #corresponding columns in X, normalized to avoid scaling issue in the PCA (if the sources amplitude is much smaller than the outliers amplitude, they may not be detected otherwise) u,s,v=np.linalg.svd(Onew,full_matrices=True)#Compute the svd, can do better than that if (s[0]-np.mean(s[1::]))/(np.var(s[1::])**0.5)>5: #if an eigenvalue is anormaly large, a source is detected Onew_=copy(Onew) Os=s[0]*(u[:,0].reshape((dS['m'],1)).dot(v[0,:].reshape((1,np.size(v[0,:]))))) #outliers contribution corresponding to this eigenvalue Onew=Onew_ - Os # outliers contribution on the m-1 remaining dimensions suppOest[np.where(suppOest>0)[0][np.linalg.norm(Onew,axis=0)< np.linalg.norm(Os,axis=0)]]=0 #release of the samples whose projection on the m-1 remaining dimensions has a smaller energy than on the axis corresponding to the largest eigenvalue else: new=0*new#no outlier ######################################### #Update the amplitudes of the outliers ######################################### R=X beta=mad(X-A.dot(S)-O)*gammaValue #threshold value of the l_2,1 norm O[:,suppOest>0]=((R)[:,suppOest>0])* (np.maximum(1-beta/(np.linalg.norm((R)[:,suppOest>0],axis=0)),0)) ######################################### #Update S and A with AMCA ######################################### A_=copy(A)#A before estimation A=np.random.randn(dS['m'],dS['n']) #randomize the initialization point A/=np.linalg.norm(A,axis=0) S,A=AMCA(X-O,A,amca)#Estimation of S, A S,A=reOrder(A,S,A_,S) # reorder the factorization (to compute the convergence metric) angle=np.arccos(np.abs(np.sum(A_*A,axis=0)))*180/np.pi convA=np.max(angle) #A has converged if the maximal angle is less than 5 IndexTot+=1 if pS['verboserAMCA']: print 'rAMCA terminates in ', IndexTot, ' iterations' return S,A,O
def rGMCA(Xini,Aini): ''' Performs the rGMCA algorithm.It estimates jointly O,S and A. It further implements a weighting scheme which penalizes the entries corrupted by outliers. Input: Xini: the observations, represented in a domain in which the sources and outliers have a sparse reprentation. Output: S: the estimated sparse sources A: the estimatedmixing matrix O: the estimated sparse outliers ''' #Initialization X=copy(Xini) A=copy(Aini) O=np.zeros((dS['m'],dS['t'])) S=np.zeros((dS['n'],dS['t'])) ######################################### #Initialization ######################################### #First outliers estimation Xabs=np.array(np.abs(X)) sigmaN=np.median(Xabs)#can do better than that iniO=(np.percentile(Xabs[Xabs>sigmaN],50))#Threshold for the first estimation of the outliers O=softThres(X-A.dot(S),iniO)#First estimation of the outliers while np.linalg.cond(S)>1e4 or np.linalg.cond(A)>1e4 or np.linalg.norm(S)==0:#first estimation of the sources S=np.array(np.abs(np.linalg.pinv(A).dot(X-O))) ini=np.array(np.percentile(S,99,1)).reshape((dS['n'],1))#threshold for each source S=softThres(S,ini) while np.linalg.cond(S)>1e4 or np.linalg.cond(A)>1e4 or np.linalg.norm(S)==0:#estimation of the mixing matrix A=data.mixingMatrix(dS['m'],dS['n']) S=np.array(np.abs(np.linalg.pinv(A).dot(X-O))) tot=99 ini=np.array(np.percentile(S,tot,1)).reshape((dS['n'],1)) S=softThres(S,ini) A=(X-O).dot(np.linalg.pinv(S)) A/=np.linalg.norm(A,axis=0) #The outliers will be thresholded by kO*mad(X-AS-O), where k decreases toward 3 kOIni= max(iniO,10)/mad(X-A.dot(S)-O)*np.ones((dS['m'],1)) #initial kO ######################################### #Joint estimation ######################################### indexIte=0 convA=10 while (convA>1 and indexIte<aS['iteMaxrGMCA']) or indexIte<5: A_=A S_=S # Decrease k# kO=kOIni+(aS['kOMax']*np.ones((dS['m'],1))-kOIni)*np.float((indexIte))/(aS['iteMaxrGMCA']-1) W=1./(np.median(np.abs(S[np.abs(S)>0]))/10.+np.linalg.norm(O,axis=0,ord=1)) #Weight for the estimation of A S,A=AMCA(X-O,A,amca=0,WO=W)#Estimate A and S O=softThres(X-A.dot(S),kO*np.median(mad(X-A.dot(S)-O)))#update of O S,A=reOrder(A,S,A_,S_)#reorder the factorization to compute the convergence metric angle=np.arccos(np.abs(np.sum(A_*A,axis=0)))*180/np.pi convA= np.max(angle) indexIte+=1 if pS['verboserGMCA']: print 'rGMCA terminates in ', indexIte, ' iterations' return S,A,O
def pcpGMCA(M, Aori, Sori, Aini): '''Algorithm performing the combination PCP+GMCA The implementation of PCP follows the one proposed in the article Robust Principal Component Analysis? of E. Candes et al. Several combinations PCP+GMCA for different values of the parameter Lambda are performed, and the best estimates are returned. Input: M: observations Aori: initial mixing matrix Sori: initial sources Aini: initializating mixing matrix for GMCA Output: S the estimated sources and A, the estimated mixing matrix ''' #Dimensions m = np.shape(M)[0] t = np.shape(M)[1] #Initialization of the variables L = M.copy() #Low rank term (corresponding to AS) O = 0 * M #outliers Y = np.zeros(np.shape(M)) #Initialization of the parameters for the loop index = 0 errorX = 20000 #Loop with the varying parameter Lambda while index < 20: Lambda = (np.float(index) / 2. + 0.5) / np.sqrt( t) #current value of lambda mu = (t * m / (4 * np.sum(np.abs(M))) ) #value of mu, given in the aticle (can do better than that) #Parameters for pcp ite = 0 convO = 10 tot = 1e16 convTot = 1e16 convL = 1 try: #Perform pcp given the current value of lambda while (ite < aS['iteMaxPCP'] and (convL > 1e-3 or convO > 1e-3 or convTot > 1e-6)) or ite < 15: #Update variables for convergence tot_ = tot #value of the cost function O_ = O #outliers L_ = L #low-rank L, S = updateL(mu, M, O, Y) # update of the low-rank term O = updateO(Lambda, mu, M, L, Y) # update of the outliers Y = Y + mu * (M - L - O ) #update Y, the Lagrange multiplier matrix # # tot = np.sum(S) + Lambda * np.sum( np.abs(O)) # update cost function convTot = np.abs( (tot - tot_)) / tot # convergence cost function convO = np.linalg.norm(O - O_) / np.linalg.norm( O_) #convergence outliers convL = np.linalg.norm(L - L_) / np.linalg.norm( L_) # convergence low-rank term ite += 1 #perform GMCA for the returned low-rank term L S, A = AMCA(L, Aini.copy(), amca=0) S, A = reOrder(A, S, Aori, Sori) deltaGMCA = np.sum( np.abs(np.linalg.pinv(A).dot(Aori) - np.eye(dS['n']))) / ( dS['n']**2) #compute the corresponding error if deltaGMCA < errorX: #If there is an improvement, keep this results errorX = deltaGMCA Sfin = S.copy() Afin = A.copy() Ofin = O.copy() if pS['verbosePCP']: print 'PCP+GMCA, current best error:', errorX, 'at index', index, 'th index in ', ite, 'iterations' elif deltaGMCA > 1.5 * errorX: #Otherwise index += 1 except np.linalg.LinAlgError: pass index += 1 return Sfin, Afin, Ofin
def trRGMCA(X,Aini,Afix=0): ''' tr-rGMCA algorithm: performs the estimations of A, S and O, based on the observations X, the number of sources n (dictionary dS['n']), and the difference of morphology between the outliers and the sources. This difference of morphology is taken into account with the transformations: Stransf, Otransf (and Sback, Oback). Inputs: - X the observations (m by t matrix) - Aini the initialized mixing matrix (m by n) - boolean Afix: if true, then the oracle is performed (no estimation of A). Otherwise, A is jointly estimated. Outputs: S (the estimated sources, n by t), A (estimated mixing matrix, m by n) and O (estimated outliers, m by t matrix). ''' O=np.zeros((dS['m'],dS['t'])) # Estimated outliers S=np.zeros((dS['n'],dS['t'])) # Estimated sources A=Aini.copy() # Estimated mixing matrix Sini=np.linalg.pinv(A).dot(X) #First estimated sources- only used to reorder the sources Siniws=Stransf(Sini)# Expansion coefficients of Sini #Expansion Coefficients of the components in the dictionary in which S is sparse Ows=Stransf(O) Sws=Stransf(S) Xws=Stransf(X) #Expansion Coefficients of the components in the dictionary in which O is sparse Owo=Otransf(O) Swo=Otransf(S) Xwo=Otransf(X) ######################################################### # Warm-up Phase or Oracle with A known # ######################################################### indexTotW=aS['Rew'] #Number of reweighting loops I=0 # Index of the outer loop (A-S// O-S) convA=10 # Criterion for the stability of A if Afix==0: #If A is estimated, set the maximal number of outer loops to 25. loopTot=25 else: loopTot=1# If A is fixed, only O and S are estimated (and the number of outer loops is set to 1) while (I<loopTot and (convA>2)) or (I<3 and Afix==0): #Stop the algorithm if the number of outer loops is too large (should not be the case), A is stable, and at least 3 outer loops have been done. I+=1 #Copy of A for convergence Aold=A.copy() #Weights for the reweightings WO=np.ones(np.shape(Owo)) WS=np.ones(np.shape(Sws)) iteMax=1000 # The maximal number of iterations for the loop estimating S and O indexW=0#Set the index of the reweighting procedure to 0 ######################## Estimation of A ################################# if Afix==0: #If A is estimated Sws,A=AMCA((Xws-Ows),A,0) #run GMCA on Xws - Ows, for estimating A and S (Sws,A)=reOrder(A,Sws,Aini,Siniws)#permutations convA=np.max(np.arccos(np.abs(np.sum(Aold*A,axis=0))/(np.linalg.norm(Aold,axis=0)*np.linalg.norm(A,axis=0)))*180/np.pi) #Maximal angle deviation from one estimation of A to another. (Should be smaller than 2 degrees to stop the algorithm). #Compute the corresponding outliers S=Sback(Sws) Swo=Otransf(S) madO=madAxis(Otransf(X-A.dot(S)-O)) normO=np.linalg.norm(Xwo-A.dot(Swo),axis=0) thr_O=np.sqrt(2)*aS['kOMax']*madO*sp.special.gamma(dS['m']/2.+0.5)/sp.special.gamma(dS['m']/2.) if np.max(normO)>thr_O: Owo=(Xwo-A.dot(Swo))*(np.maximum(1.-thr_O*WO/normO,0)) else: O*=0 Owo*=0 O=Oback(Owo) Ows=Stransf(O) L=np.linalg.norm(A.T.dot(A), 2)#Maximal eigenvalue of A.T.A ######################## EstimationS of O and S ################################# if I==1: #If this is the first loop, do not reweight indexTotW=1 else: indexTot=aS['Rew'] if Afix==1: #If A is fixed, set the number of reweighting loops to 5 indexTotW=5 else: indexTotW=1 convW=1 #criterion for the convergence of the joint O-S estimation with reweighting (based on the stability of S) ########### Reweighting ############ while indexW<indexTotW and (convW>1e-2 or indexW<2 ): # Stop the reweighting if S is stable of the number of reweighting steps is reached S_W=S.copy() # To check the stability of S if indexW==0: #Do not reweight the output of GMCA WS=np.ones((np.shape(Sws))) WO=np.ones((np.shape(Owo))) else: #Weights based on the current thresholds and components WS=np.maximum(madS*aS['kSMax'],0)/(madS*aS['kSMax']+np.abs(Sws)) WO=np.maximum(thr_O,0)/(thr_O+np.linalg.norm(Owo,axis=0)) index=0 convO=1 convS=1 ####### Estimations O and S ######## while index< iteMax and ((convO+convS)>1e-5 ): # Stop the algorithm when O and S are stable (should not reach iteMax) if index>iteMax-2 and (convA<=1e-4 or Afix==1): print 'Convergence not reached O-S' if (convO+convS)>1e-4: #Fix the parameters for convergence once the components are stable enough madS=madAxis(A.T.dot(Stransf(X-A.dot(S)-O)), axis=1) #projected noise level on the sources madO=madAxis(Otransf(X-A.dot(S)-O)) # noise level for the outliers #Copies of the components for convergence check O_=Owo.copy() S_=S.copy() ###Estimation of S, with LASSO and FISTA implementation### # Thresholds of the sources: madS*WS*aS['kSMax'] convS_sub=1 indexS=0 t_=1 y=S.copy() while convS_sub>1e-6 and indexS<5000 : S_old=S.copy() S=Sback(softThres(Stransf(y+1./L*A.T.dot(X-A.dot(y)-O)),madS*aS['kSMax']*1./L*WS,1)) t=(1.+np.sqrt(1+4*(t_)**2))/2. y=S+(t_-1.)/(t)*(S-S_old) t_=t convS_sub=np.linalg.norm(S_old-S)/np.linalg.norm(S) indexS+=1 Swo=Otransf(S) Sws=Stransf(S) ### Estimation of O ### normO=np.linalg.norm(Xwo-A.dot(Swo),axis=0) thr_O=np.sqrt(2)*aS['kOMax']*madO*sp.special.gamma(dS['m']/2.+0.5)/sp.special.gamma(dS['m']/2.) if np.max(normO)>thr_O: Owo=(Xwo-A.dot(Swo))*(np.maximum(1.-thr_O*WO/normO,0)) else: Owo*=0 O=Oback(Owo) Ows=Stransf(O) ### Convergence criteria O-S### convO=np.linalg.norm(Owo-O_)/np.linalg.norm(Owo+1e-16) convS=np.linalg.norm(S-S_)/np.linalg.norm(S+1e-16) index+=1 indexW+=1 ######Convergence reweigthing###### convW=np.linalg.norm(S-S_W)/np.linalg.norm(S) ###End warm-up### ######################################################### # Refinement # ######################################################### if Afix==0: S,A,O=palm_trRGMCA(X, O, S,A ) return S,A,O
def BetaD_ICA(xori, Aori): ''' Minization of the beta-divergence via BFGS. This implementation comes from the Matlab implementation proposed by N. Gadhok (http://home.cc.umanitoba.ca/~kinsner/projects/software/index.html) The modifications of the original code are identified as so. In particular, this version performs the minimization of the beta-divergence for different values of the beta-divergence, and returns the mixing matrix with the minimal error. Input: xori: observations Aori: initial mixing matrix, to be retrieved. Output: S: estimated sources A: estimated mixing matrix ''' #Setup parameters stopping_criterion = 1e-5 #convergence criteria maxiteration_BFGS = aS['iteMaxBeta'] #maximal number of iterations maxiteration_linesearch = 20 #maximal number of iterations for the line search #variables p_i = 2 * np.ones((dS['n'], 1)) #should be set to 2 for sparse data x = xori.copy() #copy of the observations (assumed to have zero mean) xm = x.copy() #copy of the observations (assumed to have zero mean) ### #If the number of mesures is strictly larger than the number of sources: a PCA is performed #for the reduction of dimensions ### if dS['m'] > dS['n']: U, d, V = np.linalg.svd((x).T) d2 = np.zeros((dS['n'], dS['t'])).T for index in range(0, dS['n']): d2[index, index] = d[index] x = (U[:, :].dot(d2)).T #projected observations Wred = x.dot(np.linalg.pinv((xm))) #projection matrix, identity if n=m uori = np.mean(x, 1).reshape( (dS['n'], 1)) #mean of x (should be close to 0) Wori = np.linalg.inv(Wred.dot( Aori)) #initialization of W, which should be close to the inverse of A W1 = Wori.copy() #initiliazation of demixing matrix used in the algo. u1 = uori.copy() #initiliazation of mean used in the algo. Wfinal = Wori #initialization of the returned results ufinal = uori #initialization of the returned results resultat = 1e5 #initialization of the "best" error index = 0 #index of the loop (m, t) = np.shape(x) # dimension of the matrix G = np.eye(m**2 + m) #initialization of the inverse of Hessian; #Each following loop performs a minimization given a different value of beta. while index < 400: B = 0.005 + index * 0.002 #current value of beta #Initialization of the variables and parameters W = W1.copy() u = u1.copy() v = formv(W, u) # v is a column vector corresponding of the concatenation of W and u v1 = np.zeros((m**2 + m, 1)) # v1 will be used an update of v i = 1 #index for the minimization fxO = 0 # value of the cost function at the previous iteration fx = 10 #value of the cost function fxn = 10 # vlaue of the cost function for the line search flag = 1 #Set to zero when the line search has failed prev = 1 #Previous decrease of the cost function ### #Minimization of the beta-divergence with the corresponding value of beta ### while ((prev > stopping_criterion or (np.abs(fx - fxO) / (np.abs(fxO) + 1e-16) > stopping_criterion)) and (i < maxiteration_BFGS)) or i < 10: #Main loop, which stop if convergence has been reached (decrease in the cost function smaller than stopping-criterion, twice) prev = np.abs(fx - fxO) / np.abs(fxO) #cost function decrease fxO = fx #previous value of the cost function if i > 1 and flag: #update of the variables (only if the line search was successful (implementation difference with the original implementation)) v = v1 #Update of v [W, u] = deformv(v) #Update of W and u p = -G.dot(BetaD_Deriv(x, W, u, B, p_i)) #New direction given by p ### #Begin of the line search ### alpha = 1 #line search coeffcient sigma = 1.e-4 #minimal decrease alphamin = 1.e-4 #minimal coefficient for alpha pgx = p.T.dot(BetaD_Deriv(x, W, u, B, p_i)) #decrease of the function given the direction v1 = v + alpha * p #first update of v [W2, u2] = deformv(v1) #corresponding W and u fxn = BetaD_Lbeta(x, W2, u2, B, p_i) #cost function for the first update fx = BetaD_Lbeta(x, W, u, B, p_i) #actual cost function i_linesearch = 1 #index for the line-search while (fxn > fx + sigma * alpha * pgx) and (alpha > alphamin) and ( i_linesearch < maxiteration_linesearch): mu = -0.5 * pgx * alpha / (fxn - fx - alpha * pgx) if mu < .01: mu = .5 #don't trust quadratic interpolation from far away alpha = mu * alpha v1 = v + alpha * p [W2, u2] = deformv(v1) fxn = BetaD_Lbeta(x, W2, u2, B, p_i) i_linesearch += 1 if (fxn > fx + sigma * alpha * pgx) or np.sum( np.isnan(W2) == True) > 0 or np.sum( np.isnan( BetaD_Deriv(x, W, u, B, p_i) - BetaD_Deriv(x, W2, u2, B, p_i)) == True) > 0: # Line search failed. Thus, the BFGS approx of the Hessian has become corrupt, or we are near the minimum (flat valley) and the step size is too big. So restart. G = np.eye(m**2 + m) p = -G.dot((BetaD_Deriv(x, W, u, B, p_i))) alpha = 1 flag = 0 prev += 1 #End Line search.Update accordingly the variables else: flag = 1 v1 = v + alpha * p [W, u] = deformv(v1) [W1, u1] = deformv(v) s = alpha * p y = BetaD_Deriv(x, W, u, B, p_i) - BetaD_Deriv( x, W1, u1, B, p_i) I = np.eye(m**2 + m) G = (I - (s.dot(y.T)) / ((y.T).dot(s))).dot( G.dot((I - (y.dot(s.T)) / ((y.T).dot(s))))) + (s.dot(s.T)) / ((y).T.dot(s)) #update inverse of the Hessian i += 1 [Wfinal, ufinal] = deformv(v1) #Final variables ### #Compute the corresponding sources and mixing matrix, and then the associated errors ### A = np.linalg.inv(Wfinal) #Inverse of W A = np.linalg.pinv(Wred).dot(A) # if dimension reduction was needed for indexC in range(0, dS['n']): A[:, indexC] = A[:, indexC] / np.linalg.norm( A[:, indexC]) #normalization of the columns S = np.sign(np.linalg.pinv(A).dot(xori)) * np.maximum( np.abs(np.linalg.pinv(A).dot(xori)) - aS['kSMax'] * dS['ampliN'], 0) #corresponding sources S, A = reOrder(A, S, Aori, S) # reorder the factorization D = np.sum( np.abs(np.linalg.pinv(A).dot(Aori) - np.eye(np.shape(Aori)[1])) / (dS['n']**2)) #Delta A error if D <= resultat: resultat = D Afin = A.copy() #keep the corresponding mixing matrix Sfin = S.copy() #keep the corresponding sources index += 1 if pS['verboseBeta']: print 'Beta-div.: current best result: ', D, 'at beta= 0.005+ 0.002*', index, 'in ', i, ' iterations' elif D < resultat * 1.5: index += 1 else: #exit if pS['verboseBeta']: print 'exit at ', index, 'th index' index += 400 return Sfin, Afin
def OP_GMCA(M, Aori, Sori, Aini): '''Implementation of outliers pursuit combined with GMCA. The implementation of outliers pursuit, performed for different parameters values, followed the one proposed in 'Robust PCA via Outlier Pursuit', H.Xu et al, IEEE TIT 2012. The notations taken are also the ones proposed in the aforementioned paper. Inputs: - M: the observations, of size m by t. The outliers should be sparsely represented in this domain (use Otransf, see XMCA, if needed) - Aori: the reference mixing matrix, size m by n - Sori: the reference sources (in the direct domain) (are sparely represented in DCT, via Stransf, in XMCA) - Aini: the mixing matrix for the initialization of GMCA -Outputs: -Send: the estimated sources, size n by t -Aend: estimated mixing matrix, size m by n -Oend: estimated outliers, size m by t. ''' m = np.shape(M)[0] #dimension m muOri = 0.99 * np.linalg.norm(M, 'fro') errorX = 1e5 flagExit = 0 delta = 1e-5 nu = 0.9 index = 1 muBar = delta * muOri prevRank = 0 while flagExit == 0 and index < 50: #Test for different parameter values Lambda = 1. / (np.sqrt(dS['t'])) * index / 5. #Threshold value mu = muOri t = 1. t_ = 1. k = 0 kMax = 15000 convM = 1 L = np.zeros(np.shape(M)) L_ = np.zeros(np.shape(M)) C = np.zeros(np.shape(M)) C_ = np.zeros(np.shape(M)) try: while (k < kMax and convM > 1e-5) or k < 30: #While have not converge Yl = L + (t_ - 1.) / t * (L - L_) Yc = C + (t_ - 1.) / t * (C - C_) Gl = Yl - 0.5 * (Yl + Yc - M) Gc = Yc - 0.5 * (Yl + Yc - M) L_ = L.copy() U, s2, UT = np.linalg.svd(np.dot(Gl, Gl.T), full_matrices=False) s = np.sqrt(s2) # eigenvalues of (M-O+Y*1./mu) S = np.zeros((m, m)) S[:m, :m] = np.diag(s) Sinv = S.copy() Sinv[S > 0] = 1. / S[S > 0] V = np.dot(Sinv.T, np.dot(UT, Gl)) S = softThres(S, mu / 2.) # Threshold of the eigenvalues L = np.dot(U, np.dot(S, V)) C_ = C.copy() C = Gc * np.maximum( 0, 1. - Lambda * mu / 2. / np.linalg.norm(Gc, axis=0)) t_ = t t = (1. + np.sqrt(4 * t_**2 + 1)) / 2. mu = max(nu * mu, muBar) k += 1 convM = np.linalg.norm(L - L_, 'fro') / ( np.linalg.norm(L_, 'fro') + 1e-16) + np.linalg.norm( C - C_, 'fro') / (np.linalg.norm(C_, 'fro') + 1e-16) L = XMCA.Stransf(L) #DCT/ domain in which the sources are sparse if np.linalg.matrix_rank(L) >= dS[ 'n'] and prevRank > 0: #If the low rank term, L, has a rank larger or equal to n. u, s, v = np.linalg.svd(np.dot(L, L.T)) Aini = u[:, 0:dS['n']] St, A = XMCA.AMCA(L, Aini, 0) #GMCA S = XMCA.Sback(St) S, A = reOrder(A, S, Aori, Sori) deltaGMCA = np.sum( np.abs(np.linalg.pinv(A).dot(Aori) - np.eye(dS['n']))) / ( dS['n']**2) #compute the corresponding error if deltaGMCA < errorX: #If there is an improvement, keep this results errorX = deltaGMCA Send = S.copy() Aend = A.copy() Oend = C.copy() elif deltaGMCA > 1.5 * errorX: # if the error is significantly larger than the best one, stop the algorithm index += 100 index += 1 elif np.linalg.matrix_rank( L ) == 0: # If the parameters are not correctly chosen, make a big step index += 5 elif prevRank > 0: # if we are not too far from the optimum index += 1 elif np.linalg.matrix_rank(L) >= dS[ 'n'] and prevRank == 0: #if we have made a too large step index = max(1, index - 2) else: index += 1 prevRank = np.linalg.matrix_rank(L) except np.linalg.LinAlgError: index += 1 return Send, Aend, Oend