├── Algorithm ├── CAN_code │ ├── CAN.m │ ├── PCAN.m │ ├── funs │ │ ├── ClusteringMeasure.m │ │ ├── EProjSimplex_new.m │ │ ├── L2_distance_1.m │ │ ├── eig1.m │ │ ├── kmeans_ldj.m │ │ ├── selftuning.m │ │ ├── spheres_gen.m │ │ ├── three_ring_dim_gen.m │ │ ├── three_ring_gen.m │ │ ├── threegaussian_dim_gen.m │ │ └── twogaussian_gen.m │ ├── test_CAN_toy.m │ ├── test_PCAN_toy_threering.m │ └── test_PCAN_toy_twogaussian.m ├── CLR_code │ ├── AR_55_40.mat │ ├── AR_glass.mat │ ├── AR_scarve.mat │ ├── CLR.m │ ├── constructW_PKN.m │ ├── funs │ │ ├── ClusteringMeasure.m │ │ ├── EProjSimplex_new.m │ │ ├── EProjSimplexdiag.m │ │ ├── L2_distance_1.m │ │ ├── eig1.m │ │ ├── tuneKmeans.m │ │ └── twomoon_gen.m │ ├── readme.txt │ ├── test_CLR_toy.m │ └── test_CLR_twomoons.m ├── LRR_code │ ├── demo.m │ ├── exact_alm_lrr_l1v2.m │ ├── exact_alm_lrr_l21v2.m │ ├── inexact_alm_lrr_l1.m │ ├── inexact_alm_lrr_l21.m │ ├── lrr.m │ ├── lrr_l1.m │ ├── solve_E.m │ ├── solve_l1l2.m │ └── solve_lrr.m ├── LRSR_code │ └── lrsr.m ├── LSR_code │ ├── LSR_FS │ │ ├── Data │ │ │ └── YaleB.mat │ │ ├── Experiment_FS.m │ │ ├── LSR │ │ │ ├── LSR1.m │ │ │ └── LSR2.m │ │ ├── PCA.m │ │ ├── SubspaceSegmentation.m │ │ ├── clu_ncut.m │ │ ├── compacc.m │ │ └── read me.txt │ └── LSR_MS │ │ ├── Experiment_MS.m │ │ ├── LSR │ │ ├── LSR1.m │ │ └── LSR2.m │ │ ├── PCA.m │ │ ├── SubspaceSegmentation.m │ │ ├── clu_ncut.m │ │ ├── compacc.m │ │ └── read me.txt ├── LatLRR_code │ ├── clu_ncut.m │ ├── latlrr_face_recog.m │ ├── latlrr_motion_seg.m │ ├── missclassGroups.m │ ├── rpcapsd.m │ ├── solve_latlrr.m │ └── solve_latlrra.m ├── RSS_code │ ├── data │ │ ├── USPS.mat │ │ └── YaleB.mat │ ├── demoRSS.m │ └── funs │ │ ├── EProjSimplex_new.m │ │ ├── L2_distance_1.m │ │ ├── SubClu_SimR.p │ │ ├── clu_ncut.m │ │ ├── compacc.m │ │ └── computeACC.m ├── S3C_code │ ├── ADMM_StrSSC.m │ ├── BuildAdjacency.m │ ├── DataProjection.m │ ├── Misclassification.m │ ├── SSSC.m │ ├── SpectralClusteringP.m │ ├── StrSSC.m │ ├── admm_S3C.m │ ├── compacc.m │ ├── computeLambda_mat.m │ ├── errorCoef.m │ ├── errorLinSys.m │ ├── matrixNormalize.m │ ├── missclassGroups.m │ ├── readme.txt │ ├── run_StrSSC_Faces.m │ └── thrC.m ├── SRLSR_code │ ├── SRLSR.m │ └── SimplexProj.m └── SSC_code │ ├── .DS_Store │ ├── BuildAdjacency.m │ ├── DataProjection.m │ ├── Misclassification.m │ ├── SSC.m │ ├── SimplexProj.m │ ├── YaleBCrop025.mat │ ├── admmLasso_mat_func.m │ ├── admmOutlier_mat_func.m │ ├── computeLambda_mat.m │ ├── errorCoef.m │ ├── errorLinSys.m │ ├── missclassGroups.m │ ├── readme.pdf │ ├── readme.rtf │ ├── run_SSC_Faces.m │ ├── run_SSC_MS.m │ └── thrC.m ├── Database ├── AR_55_40.mat ├── AR_glass.mat ├── AR_scarve.mat ├── CMU_PIE.mat ├── COIL100.mat ├── COIL100_10.mat ├── COIL_20.mat ├── Jaffe.mat ├── MNIST_train.mat ├── ORL.mat ├── UMIST.mat ├── Yale.mat ├── YaleB.mat ├── usps_train.mat └── usps_train_1k.mat ├── Measure ├── ACC │ ├── acc.m │ ├── bestMap.m │ └── hungarian.m └── NMI │ ├── calc_NMI.m │ ├── nmi.m │ └── nmi_jwy.m ├── Tools ├── SpectralClustering.m ├── matrixNormalize.m ├── project_simplex.m ├── prox_l1.m ├── prox_l21.m └── prox_nuclear.m └── readme.md /Algorithm/CAN_code/CAN.m: -------------------------------------------------------------------------------- 1 | % min_{A>=0, A*1=1, F'*F=I} trace(D'*A) + r*||A||^2 + 2*lambda*trace(F'*L*F) 2 | % written by Feiping Nie on 2/9/2014 3 | function [y, A, evs] = CAN(X, c, k, r, islocal) 4 | % X: dim*num data matrix, each column is a data point 5 | % c: number of clusters 6 | % k: number of neighbors to determine the initial graph, and the parameter r if r<=0 7 | % r: paremeter, which could be set to a large enough value. If r<0, then it is determined by algorithm with k 8 | % islocal: 9 | % 1: only update the similarities of the k neighbor pairs, faster 10 | % 0: update all the similarities 11 | % y: num*1 cluster indicator vector 12 | % A: num*num learned symmetric similarity matrix 13 | % evs: eigenvalues of learned graph Laplacian in the iterations 14 | 15 | % For more details, please see: 16 | % Feiping Nie, Xiaoqian Wang, Heng Huang. 17 | % Clustering and Projected Clustering with Adaptive Neighbors. 18 | % The 20th ACM SIGKDD Conference on Knowledge Discovery and Data Mining (KDD), New York, USA, 2014. 19 | 20 | 21 | 22 | NITER = 30; 23 | num = size(X,2); 24 | if nargin < 5 25 | islocal = 1; 26 | end; 27 | if nargin < 4 28 | r = -1; 29 | end; 30 | if nargin < 3 31 | k = 15; 32 | end; 33 | 34 | distX = L2_distance_1(X,X); 35 | %distX = sqrt(distX); 36 | [distX1, idx] = sort(distX,2); 37 | A = zeros(num); 38 | rr = zeros(num,1); 39 | for i = 1:num 40 | di = distX1(i,2:k+2); 41 | rr(i) = 0.5*(k*di(k+1)-sum(di(1:k))); 42 | id = idx(i,2:k+2); 43 | A(i,id) = (di(k+1)-di)/(k*di(k+1)-sum(di(1:k))+eps); 44 | end; 45 | 46 | if r <= 0 47 | r = mean(rr); 48 | end; 49 | lambda = mean(rr); 50 | 51 | A0 = (A+A')/2; 52 | D0 = diag(sum(A0)); 53 | L0 = D0 - A0; 54 | [F, temp, evs]=eig1(L0, c, 0); 55 | 56 | if sum(evs(1:c+1)) < 0.00000000001 57 | error('The original graph has more than %d connected component', c); 58 | end; 59 | 60 | for iter = 1:NITER 61 | distf = L2_distance_1(F',F'); 62 | A = zeros(num); 63 | for i=1:num 64 | if islocal == 1 65 | idxa0 = idx(i,2:k+1); 66 | else 67 | idxa0 = 1:num; 68 | end; 69 | dfi = distf(i,idxa0); 70 | dxi = distX(i,idxa0); 71 | ad = -(dxi+lambda*dfi)/(2*r); 72 | A(i,idxa0) = EProjSimplex_new(ad); 73 | end; 74 | 75 | A = (A+A')/2; 76 | D = diag(sum(A)); 77 | L = D-A; 78 | F_old = F; 79 | [F, temp, ev]=eig1(L, c, 0); 80 | evs(:,iter+1) = ev; 81 | 82 | fn1 = sum(ev(1:c)); 83 | fn2 = sum(ev(1:c+1)); 84 | if fn1 > 0.00000000001 85 | lambda = 2*lambda; 86 | elseif fn2 < 0.00000000001 87 | lambda = lambda/2; F = F_old; 88 | else 89 | break; 90 | end; 91 | 92 | end; 93 | 94 | %[labv, tem, y] = unique(round(0.1*round(1000*F)),'rows'); 95 | [clusternum, y]=graphconncomp(sparse(A)); y = y'; 96 | if clusternum ~= c 97 | sprintf('Can not find the correct cluster number: %d', c) 98 | end; 99 | 100 | -------------------------------------------------------------------------------- /Algorithm/CAN_code/PCAN.m: -------------------------------------------------------------------------------- 1 | % min_{A>=0, A*1=1, W'*St*W=I, F'*F=I} \sum_ij aij*||W'*xi-W'*xj||^2 + r*||A||^2 + 2*lambda*trace(F'*L*F) 2 | % written by Feiping Nie on 2/9/2014 3 | function [W, y, A, evs] = PCAN(X, c, d, k, r, islocal) 4 | % X: dim*num data matrix, each column is a data point 5 | % c: number of clusters 6 | % d: projected dimension 7 | % k: number of neighbors to determine the initial graph, and the parameter r if r<=0 8 | % r: paremeter, which could be set bo a large enough value. If r<0, then it is determined by algorithm with k 9 | % islocal: 10 | % 1: only update the similarities of the k neighbor pairs, the neighbor pairs are determined by the distances in the original space 11 | % 0: update all the similarities 12 | % W: dim*d projection matrix 13 | % y: num*1 cluster indicator vector 14 | % A: num*num learned symmetric similarity matrix 15 | % evs: eigenvalues of learned graph Laplacian in the iterations 16 | 17 | % For more details, please see: 18 | % Feiping Nie, Xiaoqian Wang, Heng Huang. 19 | % Clustering and Projected Clustering with Adaptive Neighbors. 20 | % The 20th ACM SIGKDD Conference on Knowledge Discovery and Data Mining (KDD), New York, USA, 2014. 21 | 22 | 23 | 24 | NITER = 30; 25 | num = size(X,2); 26 | if nargin < 6 27 | islocal = 0; 28 | end; 29 | if nargin < 5 30 | r = -1; 31 | end; 32 | if nargin < 4 33 | k = 15; 34 | end; 35 | if nargin < 3 36 | d = c-1; 37 | end; 38 | 39 | distX = L2_distance_1(X,X); 40 | %distX = sqrt(distX); 41 | [distX1, idx] = sort(distX,2); 42 | A = zeros(num); 43 | rr = zeros(num,1); 44 | for i = 1:num 45 | di = distX1(i,2:k+2); 46 | rr(i) = 0.5*(k*di(k+1)-sum(di(1:k))); 47 | id = idx(i,2:k+2); 48 | A(i,id) = (di(k+1)-di)/(k*di(k+1)-sum(di(1:k))+eps); 49 | end; 50 | 51 | if r <= 0 52 | r = mean(rr); 53 | end; 54 | lambda = r; 55 | 56 | A0 = (A+A')/2; 57 | D0 = diag(sum(A0)); 58 | L0 = D0 - A0; 59 | [F, temp, evs]=eig1(L0, c, 0); 60 | 61 | H = eye(num)-1/num*ones(num); 62 | St = X*H*X'; 63 | invSt = inv(St); 64 | M = (X*L0*X'); 65 | W = eig1(M, d, 0, 0); 66 | 67 | for iter = 1:NITER 68 | distf = L2_distance_1(F',F'); 69 | distx = L2_distance_1(W'*X,W'*X); 70 | if iter>5 71 | [temp, idx] = sort(distx,2); 72 | end; 73 | A = zeros(num); 74 | for i=1:num 75 | if islocal == 1 76 | idxa0 = idx(i,2:k+1); 77 | else 78 | idxa0 = 1:num; 79 | end; 80 | dfi = distf(i,idxa0); 81 | dxi = distx(i,idxa0); 82 | ad = -(dxi+lambda*dfi)/(2*r); 83 | A(i,idxa0) = EProjSimplex_new(ad); 84 | end; 85 | 86 | A = (A+A')/2; 87 | D = diag(sum(A)); 88 | L = D-A; 89 | 90 | M = invSt*(X*L*X'); 91 | W = eig1(M, d, 0, 0); 92 | W = W*diag(1./sqrt(diag(W'*W))); 93 | 94 | F_old = F; 95 | [F, temp, ev]=eig1(L, c, 0); 96 | evs(:,iter+1) = ev; 97 | 98 | fn1 = sum(ev(1:c)); 99 | fn2 = sum(ev(1:c+1)); 100 | if fn1 > 0.000000001 101 | lambda = 2*lambda; 102 | elseif fn2 < 0.00000000001 103 | lambda = lambda/2; F = F_old; 104 | else 105 | break; 106 | end; 107 | 108 | end; 109 | 110 | %[labv, tem, y] = unique(round(0.1*round(1000*F)),'rows'); 111 | [clusternum, y]=graphconncomp(sparse(A)); y = y'; 112 | if clusternum ~= c 113 | sprintf('Can not find the correct cluster number: %d', c) 114 | end; 115 | 116 | 117 | -------------------------------------------------------------------------------- /Algorithm/CAN_code/funs/ClusteringMeasure.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Virgeo/Graph-based-subspsce-clustering/705aaedc2ae2476c3f6e67e87e92bcc736e0934c/Algorithm/CAN_code/funs/ClusteringMeasure.m -------------------------------------------------------------------------------- /Algorithm/CAN_code/funs/EProjSimplex_new.m: -------------------------------------------------------------------------------- 1 | function [x ft] = EProjSimplex_new(v, k) 2 | 3 | % 4 | %% Problem 5 | % 6 | % min 1/2 || x - v||^2 7 | % s.t. x>=0, 1'x=1 8 | % 9 | 10 | if nargin < 2 11 | k = 1; 12 | end; 13 | 14 | ft=1; 15 | n = length(v); 16 | 17 | v0 = v-mean(v) + k/n; 18 | %vmax = max(v0); 19 | vmin = min(v0); 20 | if vmin < 0 21 | f = 1; 22 | lambda_m = 0; 23 | while abs(f) > 10^-10 24 | v1 = v0 - lambda_m; 25 | posidx = v1>0; 26 | npos = sum(posidx); 27 | g = -npos; 28 | f = sum(v1(posidx)) - k; 29 | lambda_m = lambda_m - f/g; 30 | ft=ft+1; 31 | if ft > 100 32 | x = max(v1,0); 33 | break; 34 | end; 35 | end; 36 | x = max(v1,0); 37 | 38 | else 39 | x = v0; 40 | end; -------------------------------------------------------------------------------- /Algorithm/CAN_code/funs/L2_distance_1.m: -------------------------------------------------------------------------------- 1 | % compute squared Euclidean distance 2 | % ||A-B||^2 = ||A||^2 + ||B||^2 - 2*A'*B 3 | function d = L2_distance_1(a,b) 4 | % a,b: two matrices. each column is a data 5 | % d: distance matrix of a and b 6 | 7 | 8 | 9 | if (size(a,1) == 1) 10 | a = [a; zeros(1,size(a,2))]; 11 | b = [b; zeros(1,size(b,2))]; 12 | end 13 | 14 | aa=sum(a.*a); bb=sum(b.*b); ab=a'*b; 15 | d = repmat(aa',[1 size(bb,2)]) + repmat(bb,[size(aa,2) 1]) - 2*ab; 16 | 17 | d = real(d); 18 | d = max(d,0); 19 | 20 | % % force 0 on the diagonal? 21 | % if (df==1) 22 | % d = d.*(1-eye(size(d))); 23 | % end 24 | -------------------------------------------------------------------------------- /Algorithm/CAN_code/funs/eig1.m: -------------------------------------------------------------------------------- 1 | function [eigvec, eigval, eigval_full] = eig1(A, c, isMax, isSym) 2 | 3 | if nargin < 2 4 | c = size(A,1); 5 | isMax = 1; 6 | isSym = 1; 7 | elseif c > size(A,1) 8 | c = size(A,1); 9 | end; 10 | 11 | if nargin < 3 12 | isMax = 1; 13 | isSym = 1; 14 | end; 15 | 16 | if nargin < 4 17 | isSym = 1; 18 | end; 19 | 20 | if isSym == 1 21 | A = max(A,A'); 22 | end; 23 | [v d] = eig(A); 24 | d = diag(d); 25 | %d = real(d); 26 | if isMax == 0 27 | [d1, idx] = sort(d); 28 | else 29 | [d1, idx] = sort(d,'descend'); 30 | end; 31 | 32 | idx1 = idx(1:c); 33 | eigval = d(idx1); 34 | eigvec = v(:,idx1); 35 | 36 | eigval_full = d(idx); -------------------------------------------------------------------------------- /Algorithm/CAN_code/funs/kmeans_ldj.m: -------------------------------------------------------------------------------- 1 | function [Ind, sumd, center, obj] = kmeans_ldj(M,StartIndMeanK) 2 | % each row is a data point 3 | 4 | [nSample, nFeature] = size(M); 5 | if isscalar(StartIndMeanK) 6 | % t = randperm(nSample); 7 | % StartIndMeanK = t(1:StartIndMeanK); 8 | StartIndMeanK = randsrc(nSample,1,1:StartIndMeanK); 9 | elseif nSample ~= length(StartIndMeanK) 10 | error('each row should be a data point'); 11 | end 12 | if isvector(StartIndMeanK) 13 | K = length(StartIndMeanK); 14 | if K == nSample 15 | K = max(StartIndMeanK); 16 | means = zeros(K,nFeature); 17 | for ii=1:K 18 | means(ii,:) = mean(M(find(StartIndMeanK==ii),:),1); 19 | end 20 | else 21 | means = zeros(K,nFeature); 22 | for ii=1:K 23 | means(ii,:) = M(StartIndMeanK(ii),:); 24 | end 25 | end 26 | else 27 | K = size(StartIndMeanK,1); 28 | means = StartIndMeanK; 29 | end 30 | center = means; 31 | M2 = sum(M.*M, 2)'; 32 | twoMp = 2*M'; 33 | M2b = repmat(M2,[K,1]); 34 | Center2 = sum(center.*center,2);Center2a = repmat(Center2,[1,nSample]);[xx, Ind] = min(abs(M2b + Center2a - center*twoMp)); 35 | Ind2 = Ind; 36 | it = 1; 37 | %while true 38 | while it < 2000 39 | for j = 1:K 40 | dex = find(Ind == j); 41 | l = length(dex); 42 | if l > 1; center(j,:) = mean(M(dex,:)); 43 | elseif l == 1; center(j,:) = M(dex,:); 44 | else t = randperm(nSample);center(j,:) = M(t(1),:); 45 | end; 46 | end; 47 | Center2 = sum(center.*center,2);Center2a = repmat(Center2,[1,nSample]);[dist, Ind] = min(abs(M2b + Center2a - center*twoMp)); 48 | if Ind2==Ind; 49 | break; 50 | end 51 | Ind2 = Ind; 52 | it = it+1; 53 | end 54 | sumd = zeros(K,1); 55 | for ii=1:K 56 | idx = find(Ind==ii); 57 | dist2 = dist(idx); 58 | sumd(ii) = sum(dist2); 59 | end 60 | 61 | 62 | Ind = Ind'; 63 | obj = sum(sumd); 64 | 65 | end 66 | 67 | 68 | 69 | -------------------------------------------------------------------------------- /Algorithm/CAN_code/funs/selftuning.m: -------------------------------------------------------------------------------- 1 | % self-tuning 2 | function [A An] = selftuning(X_total, k) 3 | % each row is a data point 4 | 5 | AA = L2_distance_1(X_total',X_total'); 6 | AA(find(AA<0)) = 0; 7 | clear X_total; 8 | AA = sqrt(AA); 9 | n = size(AA, 1); 10 | [dumb idx] = sort(AA, 2); % sort each row 11 | clear dumb; 12 | A = zeros(n); 13 | for i = 1:n 14 | A(i, idx(i,2:k+1)) = AA(i, idx(i,2:k+1)) + eps; 15 | end; 16 | clear AA; 17 | A = max(A, A'); 18 | %A = (A+A')/2; 19 | clear idx; 20 | 21 | % Find the count of nonzero for each column 22 | col_count = sum(A~=0, 1)'; 23 | col_sum = sum(A, 1)'; 24 | col_mean = col_sum ./ col_count; 25 | [x y val] = find(A); 26 | A = sparse(x, y, -val.*val./col_mean(x)./col_mean(y)./2); 27 | clear col_count col_sum col_mean x y val; 28 | % Do exp function sequentially because of memory limitation 29 | num = 2000; 30 | num_iter = ceil(n/num); 31 | S = sparse([]); 32 | for i = 1:num_iter 33 | start_index = 1 + (i-1)*num; 34 | end_index = min(i*num, n); 35 | S1 = spfun(@exp, A(:,start_index:end_index)); % sparse exponential func 36 | S = [S S1]; 37 | clear S1; 38 | end 39 | A = real(S); 40 | clear S; 41 | 42 | A = A + eps*speye(n); 43 | A = max(A,A'); 44 | D = diag(sum(A,2)); 45 | Dd = diag(D); 46 | clear D; 47 | Dn=spdiags(sqrt(1./Dd),0,n,n); 48 | An = Dn*A*Dn; 49 | clear Dn; 50 | An = max(An,An'); 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /Algorithm/CAN_code/funs/spheres_gen.m: -------------------------------------------------------------------------------- 1 | function [X, y] = spheres_gen(c, n, noise) 2 | % each row is a data point 3 | 4 | if nargin < 3 5 | noise = 0.03; 6 | end; 7 | 8 | k = sqrt(c); 9 | conv=noise*eye(2); 10 | m = [kron(1:k,ones(1,k)); kron(ones(1,k),1:k)]; 11 | X=[]; 12 | y=[]; 13 | for i=1:c 14 | X=[X,mvnrnd(m(:,i),conv,n/c)']; 15 | y = [y;i*ones(n/c,1)]; 16 | end 17 | 18 | X = X'; -------------------------------------------------------------------------------- /Algorithm/CAN_code/funs/three_ring_dim_gen.m: -------------------------------------------------------------------------------- 1 | function [X, y] = three_ring_dim_gen 2 | % generate three ring data 3 | fea_n = 3; 4 | n1 = 120; 5 | n2 = 220; 6 | n3 = 260; 7 | n = n1 + n2 + n3; 8 | noise1 = 0.035; 9 | noise2 = 0.13; 10 | curve = 2.5; 11 | 12 | % 2-D data 13 | r = 0.2; 14 | t = unifrnd(0,0.8,[1,n1]); 15 | x = r.*sin(curve*pi*t) + noise1*randn(1,n1); 16 | y = r.*cos(curve*pi*t) + noise1*randn(1,n1); 17 | z = 5*noise2*randn(fea_n,n1); 18 | data1 = [x;y;z]; 19 | 20 | r = 0.7; 21 | curve = 2.5; 22 | t = unifrnd(0,0.8,[1,n2]); 23 | x = r.*sin(curve*pi*t) + noise1*randn(1,n2); 24 | y = r.*cos(curve*pi*t) + noise1*randn(1,n2); 25 | z = 5*noise2*randn(fea_n,n2); 26 | data2 = [x;y;z]; 27 | 28 | r = 1.2; 29 | curve = 2.5; 30 | t = unifrnd(0,0.8,[1,n3]); 31 | x = r.*sin(curve*pi*t) + noise1*randn(1,n3); 32 | y = r.*cos(curve*pi*t) + noise1*randn(1,n3); 33 | z = 5*noise2*randn(fea_n,n3); 34 | data3 = [x;y;z]; 35 | 36 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%5 37 | 38 | % for three ring data 39 | X = [data1,data2,data3]'; 40 | y = [ones(1,n1),2*ones(1,n2),3*ones(1,n3)]; -------------------------------------------------------------------------------- /Algorithm/CAN_code/funs/three_ring_gen.m: -------------------------------------------------------------------------------- 1 | function [X, y] = three_ring_gen(n, noise1, fea_n, noise2) 2 | % generate three ring data, each row is a data 3 | 4 | n1 = floor(1/10*n); 5 | n2 = floor(3/10*n); 6 | n3 = floor(6/10*n); 7 | 8 | if nargin < 4 9 | noise2 = 0.1;%0.139; 10 | end; 11 | if nargin < 3 12 | fea_n = 1; 13 | end; 14 | if nargin < 2 15 | noise1 = 0.035; 16 | end; 17 | 18 | curve = 2.5; 19 | 20 | % 2-D data 21 | r = 0.2; 22 | t = unifrnd(0,0.8,[1,n1]); 23 | x = r.*sin(curve*pi*t) + noise1*randn(1,n1); 24 | y = r.*cos(curve*pi*t) + noise1*randn(1,n1); 25 | z = 5*noise2*randn(fea_n,n1); 26 | data1 = [x;y;z]; 27 | 28 | r = 0.6; 29 | curve = 2.5; 30 | t = unifrnd(0,0.8,[1,n2]); 31 | x = r.*sin(curve*pi*t) + noise1*randn(1,n2); 32 | y = r.*cos(curve*pi*t) + noise1*randn(1,n2); 33 | z = 5*noise2*randn(fea_n,n2); 34 | data2 = [x;y;z]; 35 | 36 | r = 1; 37 | curve = 2.5; 38 | t = unifrnd(0,0.8,[1,n3]); 39 | x = r.*sin(curve*pi*t) + noise1*randn(1,n3); 40 | y = r.*cos(curve*pi*t) + noise1*randn(1,n3); 41 | z = 5*noise2*randn(fea_n,n3); 42 | data3 = [x;y;z]; 43 | 44 | X = [data1,data2,data3]; 45 | y = [ones(n1,1);2*ones(n2,1);3*ones(n3,1)]; 46 | X = X'; 47 | if nargin < 3 48 | X = X(:,1:2); 49 | end; 50 | -------------------------------------------------------------------------------- /Algorithm/CAN_code/funs/threegaussian_dim_gen.m: -------------------------------------------------------------------------------- 1 | function [X, y, n1, n2, n3] = threegaussian_dim_gen(num, var1, fea_n, noise) 2 | 3 | n1 = floor(num/3); 4 | m = [-1,0]; 5 | C = [var1,0;0,var1]; 6 | x1 = mvnrnd(m,C,n1); 7 | 8 | m = [1,0]; 9 | x2 = mvnrnd(m,C,n1); 10 | 11 | m = [0,1]; 12 | x3 = mvnrnd(m,C,n1); 13 | 14 | z = 5*noise*randn(3*n1,fea_n); 15 | 16 | X = [[x1;x2;x3],z]; 17 | 18 | n2 = n1; 19 | n3 = n1; 20 | y = [ones(n1,1);2*ones(n2,1);3*ones(n3,1)]; -------------------------------------------------------------------------------- /Algorithm/CAN_code/funs/twogaussian_gen.m: -------------------------------------------------------------------------------- 1 | function [X, n1] = twogaussian_gen(num, interval1, interval2, var1, var2) 2 | 3 | n1 = floor(num/2); 4 | m = [-interval1,interval2]; 5 | C = [var1,0;0,var2]; 6 | x1 = mvnrnd(m,C,n1); 7 | 8 | m = [interval1,-interval2]; 9 | x2 = mvnrnd(m,C,n1); 10 | 11 | X = [x1;x2]; -------------------------------------------------------------------------------- /Algorithm/CAN_code/test_CAN_toy.m: -------------------------------------------------------------------------------- 1 | clc; 2 | close all; 3 | 4 | folder_now = pwd; addpath([folder_now, '\funs']); 5 | 6 | newdata = 1; 7 | datatype = 2; % 1: two-moon data, 2: three-ring data, 3: 196-cluster data 8 | 9 | if newdata == 1 10 | clearvars -except datatype; 11 | 12 | if datatype == 1 13 | num0 = 100; X = twomoon_gen(num0); c = 2; y = [ones(num0,1);2*ones(num0,1)]; 14 | elseif datatype == 2 15 | num0 = 500; [X, y] = three_ring_gen(num0,0.05); c = 3; 16 | else 17 | c=196; [X, y] = spheres_gen(c, c*10, 0.03); 18 | end; 19 | end; 20 | 21 | 22 | [la, A, evs] = CAN(X', c); 23 | figure('name','Learned graph by CAN'); 24 | imshow(A,[]); colormap jet; colorbar; 25 | 26 | cm = colormap(jet(c)); 27 | figure('name','Clustering results by CAN'); 28 | plot(X(:,1),X(:,2),'.k'); hold on; 29 | 30 | rl = randperm(c); 31 | for i=1:c 32 | plot(X(la==rl(i),1),X(la==rl(i),2),'.', 'color', cm(i,:)); hold on; 33 | end; 34 | result_can = ClusteringMeasure(y, la); 35 | [ind,sumd,center, ob_can] = kmeans_ldj(X,la); 36 | result_cankm0 = ClusteringMeasure(y, ind); 37 | result_cankm = [result_cankm0(1), ob_can] 38 | 39 | % km clustering 40 | if datatype==3 41 | for i=1:100 42 | [ind0(:,i),sumd,center0(:,:,i),ob(i)] = kmeans_ldj(X,c); 43 | end; 44 | ob1=sort(ob); 45 | [obkm_best, idx_best] = min(ob); 46 | y1 = ind0(:,idx_best); 47 | result_km0 = ClusteringMeasure(y, y1); 48 | result_km = [result_km0(1), obkm_best] 49 | 50 | cm = colormap(jet(c)); 51 | figure('name','Clustering results by Kmeans'); 52 | rl = randperm(c); 53 | for i=1:c 54 | plot(X(y1==rl(i),1),X(y1==rl(i),2),'.', 'color', cm(i,:)); hold on; 55 | end; 56 | 57 | end; 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /Algorithm/CAN_code/test_PCAN_toy_threering.m: -------------------------------------------------------------------------------- 1 | clc; 2 | close all; 3 | 4 | folder_now = pwd; addpath([folder_now, '\funs']); 5 | 6 | newdata = 1; 7 | datatype = 1; % 1: three-Gaussian data, 2: three-ring data 8 | 9 | if newdata == 1 10 | clearvars -except datatype; 11 | 12 | if datatype == 1 13 | [X, y, n1, n2, n3] = threegaussian_dim_gen(300, 0.05, 10, 0.5); c = 3; 14 | else 15 | [X, y] = three_ring_dim_gen; c = 3; 16 | end; 17 | end; 18 | 19 | 20 | [W, la, A, evs] = PCAN(X', c); 21 | 22 | X1 = X*W; 23 | figure('name','Learned subspace and clustering by PCAN'); 24 | plot(X1(:,1),X1(:,2),'.k'); hold on; 25 | cm = colormap(jet(c)); 26 | for i = 1:c 27 | plot(X1(la==i,1),X1(la==i,2),'.', 'color', cm(i,:)); hold on; 28 | end; 29 | axis equal; 30 | 31 | 32 | % pca 33 | num = size(X,1); 34 | H = eye(num)-1/num*ones(num); 35 | St = X'*H; 36 | [U, S, V] = svd(St,'econ'); s = diag(S); 37 | X2 = X*U(:,1:2); 38 | figure('name','Learned subspace by PCA'); 39 | plot(X2(:,1),X2(:,2),'.k'); hold on; 40 | for i = 1:c 41 | plot(X2(y==i,1),X2(y==i,2),'.', 'color', cm(i,:)); hold on; 42 | end; 43 | axis equal; 44 | 45 | 46 | 47 | % lpp 48 | H = eye(num)-1/num*ones(num); 49 | St =X'*H*X; 50 | invSt = inv(St); 51 | A = selftuning(X, 10); 52 | L = diag(sum(A,2))-A; 53 | Sl = X'*L*X; 54 | M = invSt*Sl; 55 | [W, temp, ev]=eig1(M, 2, 0, 0); 56 | W = W*diag(1./sqrt(diag(W'*W))); 57 | X3 = X*W; 58 | figure('name','Learned subspace by LPP'); 59 | plot(X3(:,1),X3(:,2),'.k'); hold on; 60 | for i = 1:c 61 | plot(X3(y==i,1),X3(y==i,2),'.', 'color', cm(i,:)); hold on; 62 | end; 63 | axis equal; 64 | -------------------------------------------------------------------------------- /Algorithm/CAN_code/test_PCAN_toy_twogaussian.m: -------------------------------------------------------------------------------- 1 | clc; 2 | close all; 3 | 4 | folder_now = pwd; addpath([folder_now, '\funs']); 5 | 6 | newdata = 1; 7 | if newdata == 1 8 | clear; 9 | num0 = 200; 10 | [X, n1] = twogaussian_gen(num0, 0.99, 0.0, .1, 5); c = 2; 11 | end; 12 | 13 | 14 | [W, la, A, evs] = PCAN(X', c); 15 | figure('name','Learned graph by PCAN'); 16 | imshow(A,[]); colormap jet; colorbar; 17 | 18 | 19 | figure('name','Projected directions by PCAN, PCA and LPP'); 20 | set(gca, 'fontsize',15); 21 | %plot(X(:,1),X(:,2),'.k'); hold on; 22 | plot(X(la==1,1),X(la==1,2),'.r','MarkerSize',15); hold on; 23 | plot(X(la==2,1),X(la==2,2),'.b','MarkerSize',15); hold on; 24 | plot(X(la==3,1),X(la==3,2),'.g','MarkerSize',15); hold on; 25 | minx = 1.5*min(X(:,1)); maxx = 1.5*max(X(:,1)); 26 | miny = 1.1*min(X(:,2)); maxy = 1.1*max(X(:,2)); 27 | if abs(W(1))>abs(W(2)) 28 | h1 = plot([minx, maxx],[W(2)/W(1)*minx, W(2)/W(1)*maxx],'c','LineWidth',2,'MarkerSize',15); hold on; 29 | else 30 | h1 = plot([W(1)/W(2)*miny, W(1)/W(2)*maxy], [miny, maxy],'c','LineWidth',2,'MarkerSize',15); hold on; 31 | end; 32 | axis equal; 33 | 34 | 35 | % pca 36 | num = size(X,1); 37 | H = eye(num)-1/num*ones(num); 38 | St = X'*H; 39 | [U, S, V] = svd(St,'econ'); s = diag(S); 40 | W = U(:,1); 41 | if abs(W(1))>abs(W(2)) 42 | h2 = plot([minx, maxx],[W(2)/W(1)*minx, W(2)/W(1)*maxx],'g','LineWidth',2,'MarkerSize',15); hold on; 43 | else 44 | h2 = plot([W(1)/W(2)*miny, W(1)/W(2)*maxy], [miny, maxy],'g','LineWidth',2,'MarkerSize',15); hold on; 45 | end; 46 | axis equal; 47 | 48 | 49 | 50 | % lpp 51 | H = eye(num)-1/num*ones(num); 52 | St =X'*H*X; 53 | invSt = inv(St); 54 | A = selftuning(X, 10); 55 | L = diag(sum(A,2))-A; 56 | Sl = X'*L*X; 57 | M = invSt*Sl; 58 | [W, temp, ev]=eig1(M, 2, 0, 0); 59 | W = W*diag(1./sqrt(diag(W'*W))); 60 | if abs(W(1))>abs(W(2)) 61 | h3 = plot([minx, maxx],[W(2)/W(1)*minx, W(2)/W(1)*maxx],'m','LineWidth',2,'MarkerSize',15); hold on; 62 | else 63 | h3 = plot([W(1)/W(2)*miny, W(1)/W(2)*maxy], [miny, maxy],'m','LineWidth',2,'MarkerSize',15); hold on; 64 | end; 65 | axis equal; 66 | 67 | legend([h1,h2,h3],'PCAN','PCA','LPP',4); 68 | -------------------------------------------------------------------------------- /Algorithm/CLR_code/AR_55_40.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Virgeo/Graph-based-subspsce-clustering/705aaedc2ae2476c3f6e67e87e92bcc736e0934c/Algorithm/CLR_code/AR_55_40.mat -------------------------------------------------------------------------------- /Algorithm/CLR_code/AR_glass.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Virgeo/Graph-based-subspsce-clustering/705aaedc2ae2476c3f6e67e87e92bcc736e0934c/Algorithm/CLR_code/AR_glass.mat -------------------------------------------------------------------------------- /Algorithm/CLR_code/AR_scarve.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Virgeo/Graph-based-subspsce-clustering/705aaedc2ae2476c3f6e67e87e92bcc736e0934c/Algorithm/CLR_code/AR_scarve.mat -------------------------------------------------------------------------------- /Algorithm/CLR_code/CLR.m: -------------------------------------------------------------------------------- 1 | % min_{S>=0, S*1=1, F'*F=I} ||S - A||^2 + r*||S||^2 + 2*lambda*trace(F'*L*F) 2 | % or 3 | % min_{S>=0, S*1=1, F'*F=I} ||S - A||_1 + r*||S||^2 + 2*lambda*trace(F'*L*F) 4 | function [y, S, evs, cs] = CLR(A0, c, isrobust, islocal) 5 | % A0: the given affinity matrix 6 | % c: cluster number 7 | % isrobust: solving the second (L1 based) problem if isrobust=1 8 | % islocal: only update the similarities of neighbors if islocal=1 9 | % y: the final clustering result, cluster indicator vector 10 | % S: learned symmetric similarity matrix 11 | % evs: eigenvalues of learned graph Laplacian in the iterations 12 | % cs: suggested cluster numbers, effective only when the cluster structure is clear 13 | 14 | % Ref: 15 | % Feiping Nie, Xiaoqian Wang, Michael I. Jordan, Heng Huang. 16 | % The Constrained Laplacian Rank Algorithm for Graph-Based Clustering. 17 | % The 30th Conference on Artificial Intelligence (\textbf{AAAI}), Phoenix, USA, 2016. 18 | 19 | 20 | NITER = 30; 21 | zr = 10e-11; 22 | lambda = 0.1; 23 | r = 0; 24 | 25 | if nargin < 4 26 | islocal = 1; 27 | end; 28 | if nargin < 3 29 | isrobust = 0; 30 | end; 31 | 32 | A0 = A0-diag(diag(A0)); 33 | num = size(A0,1); 34 | A10 = (A0+A0')/2; 35 | D10 = diag(sum(A10)); 36 | L0 = D10 - A10; 37 | 38 | % automatically determine the cluster number 39 | [F0, ~, evs]=eig1(L0, num, 0); 40 | a = abs(evs); a(a0.85)=1; ad1 = ad1+eps*(1:num-1)'; ad1(1)=0; ad1 = ad1(1:floor(0.9*end)); 43 | [te, cs] = sort(ad1,'descend'); 44 | % sprintf('Suggested cluster number is: %d, %d, %d, %d, %d', cs(1),cs(2),cs(3),cs(4),cs(5)) 45 | if nargin == 1 46 | c = cs(1); 47 | end; 48 | F = F0(:,1:c); 49 | if sum(evs(1:c+1)) < zr 50 | error('The original graph has more than %d connected component', c); 51 | end; 52 | if sum(evs(1:c)) < zr 53 | [clusternum, y]=graphconncomp(sparse(A10)); y = y'; 54 | S = A0; 55 | return; 56 | end; 57 | 58 | for i=1:num 59 | a0 = A0(i,:); 60 | if islocal == 1 61 | idxa0 = find(a0>0); 62 | else 63 | idxa0 = 1:num; 64 | end; 65 | u{i} = ones(1,length(idxa0)); 66 | end; 67 | 68 | 69 | for iter = 1:NITER 70 | dist = L2_distance_1(F',F'); 71 | S = zeros(num); 72 | for i=1:num 73 | a0 = A0(i,:); 74 | if islocal == 1 75 | idxa0 = find(a0>0); 76 | else 77 | idxa0 = 1:num; 78 | end; 79 | ai = a0(idxa0); 80 | di = dist(i,idxa0); 81 | if isrobust == 1 82 | for ii = 1:1 83 | ad = u{i}.*ai-lambda*di/2; 84 | si = EProjSimplexdiag(ad, u{i}+r*ones(1,length(idxa0))); 85 | u{i} = 1./(2*sqrt((si-ai).^2+eps)); 86 | end; 87 | S(i,idxa0) = si; 88 | else 89 | ad = ai-0.5*lambda*di; S(i,idxa0) = EProjSimplex_new(ad); 90 | end; 91 | end; 92 | A = S; 93 | A = (A+A')/2; 94 | D = diag(sum(A)); 95 | L = D-A; 96 | F_old = F; 97 | [F, ~, ev]=eig1(L, c, 0); 98 | evs(:,iter+1) = ev; 99 | 100 | fn1 = sum(ev(1:c)); 101 | fn2 = sum(ev(1:c+1)); 102 | if fn1 > zr 103 | lambda = 2*lambda; 104 | elseif fn2 < zr 105 | lambda = lambda/2; F = F_old; 106 | else 107 | break; 108 | end; 109 | end; 110 | 111 | %[labv, tem, y] = unique(round(0.1*round(1000*F)),'rows'); 112 | [clusternum, y]=graphconncomp(sparse(A)); y = y'; 113 | if clusternum ~= c 114 | sprintf('Can not find the correct cluster number: %d', c) 115 | end; 116 | 117 | 118 | -------------------------------------------------------------------------------- /Algorithm/CLR_code/constructW_PKN.m: -------------------------------------------------------------------------------- 1 | % construct similarity matrix with probabilistic k-nearest neighbors. It is a parameter free, distance consistent similarity. 2 | function W = constructW_PKN(X, k, issymmetric) 3 | % X: each column is a data point 4 | % k: number of neighbors 5 | % issymmetric: set W = (W+W')/2 if issymmetric=1 6 | % W: similarity matrix 7 | 8 | if nargin < 3 9 | issymmetric = 1; 10 | end; 11 | if nargin < 2 12 | k = 5; 13 | end; 14 | 15 | [dim, n] = size(X); 16 | D = L2_distance_1(X, X); 17 | [dumb, idx] = sort(D, 2); % sort each row 18 | 19 | W = zeros(n); 20 | for i = 1:n 21 | id = idx(i,2:k+2); 22 | di = D(i, id); 23 | W(i,id) = (di(k+1)-di)/(k*di(k+1)-sum(di(1:k))+eps); 24 | end; 25 | 26 | if issymmetric == 1 27 | W = (W+W')/2; 28 | end; 29 | 30 | 31 | 32 | 33 | % compute squared Euclidean distance 34 | % ||A-B||^2 = ||A||^2 + ||B||^2 - 2*A'*B 35 | function d = L2_distance_1(a,b) 36 | % a,b: two matrices. each column is a data 37 | % d: distance matrix of a and b 38 | 39 | 40 | 41 | if (size(a,1) == 1) 42 | a = [a; zeros(1,size(a,2))]; 43 | b = [b; zeros(1,size(b,2))]; 44 | end 45 | 46 | aa=sum(a.*a); bb=sum(b.*b); ab=a'*b; 47 | d = repmat(aa',[1 size(bb,2)]) + repmat(bb,[size(aa,2) 1]) - 2*ab; 48 | 49 | d = real(d); 50 | d = max(d,0); 51 | 52 | % % force 0 on the diagonal? 53 | % if (df==1) 54 | % d = d.*(1-eye(size(d))); 55 | % end 56 | 57 | 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /Algorithm/CLR_code/funs/ClusteringMeasure.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Virgeo/Graph-based-subspsce-clustering/705aaedc2ae2476c3f6e67e87e92bcc736e0934c/Algorithm/CLR_code/funs/ClusteringMeasure.m -------------------------------------------------------------------------------- /Algorithm/CLR_code/funs/EProjSimplex_new.m: -------------------------------------------------------------------------------- 1 | function [x ft] = EProjSimplex_new(v, k) 2 | 3 | % 4 | %% Problem 5 | % 6 | % min 1/2 || x - v||^2 7 | % s.t. x>=0, 1'x=k 8 | % 9 | 10 | if nargin < 2 11 | k = 1; 12 | end; 13 | 14 | ft=1; 15 | n = length(v); 16 | 17 | v0 = v-mean(v) + k/n; 18 | %vmax = max(v0); 19 | vmin = min(v0); 20 | if vmin < 0 21 | f = 1; 22 | lambda_m = 0; 23 | while abs(f) > 10^-10 24 | v1 = v0 - lambda_m; 25 | posidx = v1>0; 26 | npos = sum(posidx); 27 | g = -npos; 28 | f = sum(v1(posidx)) - k; 29 | lambda_m = lambda_m - f/g; 30 | ft=ft+1; 31 | if ft > 100 32 | x = max(v1,0); 33 | break; 34 | end; 35 | end; 36 | x = max(v1,0); 37 | 38 | else 39 | x = v0; 40 | end; -------------------------------------------------------------------------------- /Algorithm/CLR_code/funs/EProjSimplexdiag.m: -------------------------------------------------------------------------------- 1 | function [x, f] = EProjSimplexdiag(d, u) 2 | 3 | % 4 | %% Problem 5 | % 6 | % min 1/2*x'*U*x-x'*d 7 | % s.t. x>=0, 1'x=1 8 | % 9 | 10 | lambda = min(u-d); 11 | f = 1; 12 | count=1; 13 | while abs(f) > 10^-8 14 | v1 = 1./u*lambda+d./u; 15 | posidx = v1>0; 16 | g = sum(1./u(posidx)); 17 | f = sum(v1(posidx))-1; 18 | lambda = lambda - f/g; 19 | 20 | if count > 1000 21 | break; 22 | end; 23 | count=count+1; 24 | end; 25 | v1 = 1./u*lambda+d./u; 26 | x = max(v1,0); 27 | -------------------------------------------------------------------------------- /Algorithm/CLR_code/funs/L2_distance_1.m: -------------------------------------------------------------------------------- 1 | % compute squared Euclidean distance 2 | % ||A-B||^2 = ||A||^2 + ||B||^2 - 2*A'*B 3 | function d = L2_distance_1(a,b) 4 | % a,b: two matrices. each column is a data 5 | % d: distance matrix of a and b 6 | 7 | 8 | 9 | if (size(a,1) == 1) 10 | a = [a; zeros(1,size(a,2))]; 11 | b = [b; zeros(1,size(b,2))]; 12 | end 13 | 14 | aa=sum(a.*a); bb=sum(b.*b); ab=a'*b; 15 | d = repmat(aa',[1 size(bb,2)]) + repmat(bb,[size(aa,2) 1]) - 2*ab; 16 | 17 | d = real(d); 18 | d = max(d,0); 19 | 20 | % % force 0 on the diagonal? 21 | % if (df==1) 22 | % d = d.*(1-eye(size(d))); 23 | % end 24 | -------------------------------------------------------------------------------- /Algorithm/CLR_code/funs/eig1.m: -------------------------------------------------------------------------------- 1 | function [eigvec, eigval, eigval_full] = eig1(A, c, isMax, isSym) 2 | 3 | if nargin < 2 4 | c = size(A,1); 5 | isMax = 1; 6 | isSym = 1; 7 | elseif c > size(A,1) 8 | c = size(A,1); 9 | end; 10 | 11 | if nargin < 3 12 | isMax = 1; 13 | isSym = 1; 14 | end; 15 | 16 | if nargin < 4 17 | isSym = 1; 18 | end; 19 | 20 | if isSym == 1 21 | A = max(A,A'); 22 | end; 23 | [v d] = eig(A); 24 | d = diag(d); 25 | %d = real(d); 26 | if isMax == 0 27 | [d1, idx] = sort(d); 28 | else 29 | [d1, idx] = sort(d,'descend'); 30 | end; 31 | 32 | idx1 = idx(1:c); 33 | eigval = d(idx1); 34 | eigvec = v(:,idx1); 35 | 36 | eigval_full = d(idx); -------------------------------------------------------------------------------- /Algorithm/CLR_code/funs/tuneKmeans.m: -------------------------------------------------------------------------------- 1 | function [finalInd, Ind, kmobj, minob] = tuneKmeans(M, Ini) 2 | 3 | minob = 1e5; 4 | nIni = size(Ini, 2); 5 | kmobj = zeros(nIni); 6 | 7 | for ii = 1 : nIni 8 | [Ind(:, ii), iter_num, sumd, center, obj] = kmeans(M', Ini(:, ii)); 9 | kmobj(ii) = obj; 10 | if obj < minob 11 | minob = obj; 12 | finalInd = Ind(:, ii); 13 | end; 14 | end; 15 | 16 | end 17 | 18 | -------------------------------------------------------------------------------- /Algorithm/CLR_code/funs/twomoon_gen.m: -------------------------------------------------------------------------------- 1 | function [input,y] = twomoon_gen(num1, num2, sigma_noise, horizonal, vertical) 2 | 3 | if nargin == 1 4 | num2 = num1; 5 | end; 6 | if nargin <= 2 7 | sigma_noise = 0.125; 8 | end; 9 | if nargin <= 3 10 | level = 0.35; 11 | upright = 0.15; 12 | else 13 | level = 0.32+horizonal; 14 | upright = 0.15+vertical; 15 | end; 16 | t=pi:-pi/(num1-1):0; 17 | input(1:num1, 1) = cos(t)'+randn(num1,1)*sigma_noise - level; 18 | input(1:num1, 2) = sin(t)'+randn(num1,1)*sigma_noise - upright; 19 | 20 | t=pi:pi/(num2-1):2*pi; 21 | input(num1+1:num1+num2, 1) = cos(t)'+randn(num2,1)*sigma_noise + level; 22 | input(num1+1:num1+num2, 2) = sin(t)'+randn(num2,1)*sigma_noise + upright; 23 | 24 | y = [ones(num1,1); -1*ones(num2,1)]; 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /Algorithm/CLR_code/readme.txt: -------------------------------------------------------------------------------- 1 | constructW_PKN: 2 | A parameter free graph construction method with probabilistic k-nearest neighbors. Graph construction is a fundamental and the most important problem in graph based learning methods. The constructed graph with this function can be used in other graph based learning methods. 3 | 4 | CLR: 5 | The Constrained Laplacian Rank algorithm 6 | 7 | test_CLR_toy: 8 | Experiments on toy data 9 | 10 | test_CLR_twomoons: 11 | Experiments on two-moon data -------------------------------------------------------------------------------- /Algorithm/CLR_code/test_CLR_toy.m: -------------------------------------------------------------------------------- 1 | clc; close all; 2 | currentFolder = pwd; 3 | addpath(genpath(currentFolder)); 4 | 5 | newdata = 1; 6 | if newdata == 1 7 | clear; 8 | %% Data Generalization 9 | n = 100; % Total number of points 10 | c = 4; % Number of clusters 11 | n1 = n/c; 12 | noisePortion = 0.85; 13 | noise = noisePortion*rand(n) + 10*blkdiag(ones(n1),ones(n1),ones(n1),ones(n1)); 14 | noise(noise>1) = 0; 15 | c1=1;A=blkdiag(c1*rand(n1),c1*rand(n1),c1*rand(n1),c1*rand(n1)) + noise; 16 | 17 | % Randomly set 20 noise points to 1 18 | A(1,100)=1; A(51,16)=1; A(76,12)=1; A(1,87)=1; A(3,95)=1; A(30,1)=1; A(77,9)=1; A(50,22)=1; A(8,88)=1; A(21,93)=1; A(45,8)=1; A(27,91)=1; 19 | A(17,97)=1; A(53,11)=1; A(34,4)=1; A(28,67)=1; A(24,71)=1; A(2,78)=1; A(75,18)=1; A(17,99)=1; 20 | 21 | A = A - diag(diag(A)); 22 | A0 = A; 23 | A = (A+A')/2; 24 | else 25 | A = A0; 26 | end; 27 | 28 | y0 = [ones(n1,1);2*ones(n1,1);3*ones(n1,1);4*ones(n1,1)]; 29 | 30 | figure; imshow(A,[]); colormap jet; colorbar; 31 | set(gcf,'outerposition',get(0,'screensize')); 32 | 33 | isrobust = 0; 34 | [y, S, evs, cs] = CLR(A0, c, isrobust); 35 | result_CLR0 = ClusteringMeasure(y0, y) 36 | %n = histc(y,unique(y))' 37 | 38 | figure; imshow(S,[]); colormap jet; colorbar; 39 | set(gcf,'outerposition',get(0,'screensize')); 40 | 41 | isrobust = 1; 42 | [y, S, evs, cs] = CLR(A0, c, isrobust); 43 | result_CLR1 = ClusteringMeasure(y0, y) 44 | %n = histc(y,unique(y))' 45 | 46 | figure; imshow(S,[]); colormap jet; colorbar; 47 | set(gcf,'outerposition',get(0,'screensize')); 48 | 49 | 50 | 51 | % RCut & NCut 52 | D = diag(sum(A)); 53 | nRepeat = 100; 54 | Ini = zeros(n, nRepeat); 55 | for jj = 1 : nRepeat 56 | Ini(:, jj) = randsrc(n, 1, 1:c); 57 | end; 58 | 59 | % RCut 60 | fprintf('Ratio Cut\n'); 61 | [Fg, tmpD] = eig1(full(D-A), c, 0, 1); 62 | Fg = Fg./repmat(sqrt(sum(Fg.^2,2)),1,c); %optional 63 | y = tuneKmeans(Fg, Ini); 64 | result_RCut = ClusteringMeasure(y0, y) 65 | 66 | % NCut 67 | fprintf('Normalized Cut\n'); 68 | Dd = diag(D); 69 | Dn = spdiags(sqrt(1./Dd),0,n,n); 70 | An = Dn*A*Dn; 71 | An = (An+An')/2; 72 | [Fng, D] = eig1(full(An), c, 1, 1); 73 | Fng = Fng./repmat(sqrt(sum(Fng.^2,2)),1,c); %optional 74 | y = tuneKmeans(Fng, Ini); 75 | result_NCut = ClusteringMeasure(y0, y) 76 | 77 | 78 | -------------------------------------------------------------------------------- /Algorithm/CLR_code/test_CLR_twomoons.m: -------------------------------------------------------------------------------- 1 | % Toy experiment on the two-moon synthetic data. 2 | % Feiping Nie, Xiaoqian Wang, Michael I. Jordan, Heng Huang. 3 | % The Constrained Laplacian Rank Algorithm for Graph-Based Clustering. 4 | % The Thirtieth AAAI Conference on Artificial Intelligence (AAAI-16) 5 | 6 | clc; close all; 7 | currentFolder = pwd; 8 | addpath(genpath(currentFolder)); 9 | 10 | newdata = 1; 11 | if newdata == 1 12 | clear 13 | %% Data Generalization 14 | num0 = 100; 15 | X = twomoon_gen(num0); 16 | y0 = [ones(num0,1);2*ones(num0,1)]; 17 | c = 2; 18 | end; 19 | 20 | A0 = constructW_PKN(X', 10, 0); 21 | A = A0; 22 | A = (A+A')/2; 23 | 24 | la = y0; 25 | % The original data 26 | MS = 18; 27 | figure; 28 | plot(X(:,1),X(:,2),'.k', 'MarkerSize', MS); hold on; 29 | plot(X(la==1,1),X(la==1,2),'.b', 'MarkerSize', MS); hold on; 30 | plot(X(la==2,1),X(la==2,2),'.r', 'MarkerSize', MS); hold on; 31 | axis equal; 32 | 33 | % Probabilistic neighbors, line width denotes similarity 34 | figure; 35 | plot(X(:,1),X(:,2),'.k', 'MarkerSize', MS); hold on; 36 | plot(X(la==1,1),X(la==1,2),'.b', 'MarkerSize', MS); hold on; 37 | plot(X(la==2,1),X(la==2,2),'.r', 'MarkerSize', MS); hold on; 38 | nn = 2*num0; 39 | for ii = 1 : nn; 40 | for jj = 1 : ii 41 | weight = A(ii, jj); 42 | if weight > 0 43 | plot([X(ii, 1), X(jj, 1)], [X(ii, 2), X(jj, 2)], '-g', 'LineWidth', 15*weight), hold on; 44 | end 45 | end; 46 | end; 47 | axis equal; 48 | 49 | [y, S, evs, cs] = CLR(A0, c); 50 | A = (S+S')/2; 51 | 52 | % Adaptive neighbors with L2, line width denotes similarity 53 | figure; 54 | plot(X(:,1),X(:,2),'.k', 'MarkerSize', MS); hold on; 55 | plot(X(la==1,1),X(la==1,2),'.b', 'MarkerSize', MS); hold on; 56 | plot(X(la==2,1),X(la==2,2),'.r', 'MarkerSize', MS); hold on; 57 | nn = 2*num0; 58 | for ii = 1 : nn; 59 | for jj = 1 : ii 60 | weight = A(ii, jj); 61 | if weight > 0 62 | plot([X(ii, 1), X(jj, 1)], [X(ii, 2), X(jj, 2)], '-g', 'LineWidth', 15*weight), hold on; 63 | end 64 | end; 65 | end; 66 | axis equal; 67 | -------------------------------------------------------------------------------- /Algorithm/LRR_code/demo.m: -------------------------------------------------------------------------------- 1 | function [] = demo() 2 | A = randn(100,200); 3 | X = randn(100,100); 4 | lambda = 0.01; 5 | 6 | disp('solve min |Z|_* + lambda |E|_21 s.t. X = AZ + E by exact ALM ...'); 7 | 8 | tic; 9 | [Z1,E1] = solve_lrr(X,A,lambda,0,0); 10 | obj1 = sum(svd(Z1)) + lambda*sum(sqrt(sum(E1.^2,1))); 11 | toc; 12 | 13 | disp(['objective value=' num2str(obj1)]); 14 | 15 | disp('solve min |Z|_* + lambda |E|_21 s.t. X = AZ + E by inexact ALM ...'); 16 | 17 | tic; 18 | [Z2,E2] = solve_lrr(X,A,lambda,0,1); 19 | obj2 = sum(svd(Z2)) + lambda*sum(sqrt(sum(E2.^2,1))); 20 | toc; 21 | disp(['objective value=' num2str(obj2)]); 22 | 23 | diff = max(max(abs(Z1 - Z2))); 24 | 25 | warning(['difference of the solution found by those two approaches: |Z1 - Z2|_inf=' num2str(diff)]); 26 | 27 | disp('solve min |Z|_* + lambda |E|_1 s.t. X = AZ + E by exact ALM ...'); 28 | tic; 29 | [Z1,E1] = solve_lrr(X,A,lambda,1,0); 30 | obj1 = sum(svd(Z1)) + lambda*sum(sqrt(sum(E1.^2,1))); 31 | toc; 32 | 33 | disp(['objective value=' num2str(obj1)]); 34 | 35 | disp('solve min |Z|_* + lambda |E|_1 s.t. X = AZ + E by inexact ALM ...'); 36 | tic; 37 | [Z2,E2] = solve_lrr(X,A,lambda,1,1); 38 | obj2 = sum(svd(Z2)) + lambda*sum(sqrt(sum(E2.^2,1))); 39 | toc; 40 | disp(['objective value=' num2str(obj2)]); 41 | 42 | diff = max(max(abs(Z1 - Z2))); 43 | 44 | warning(['difference of the solution found by those two approaches: |Z1 - Z2|_inf=' num2str(diff) ]); 45 | -------------------------------------------------------------------------------- /Algorithm/LRR_code/exact_alm_lrr_l1v2.m: -------------------------------------------------------------------------------- 1 | function [Z_hat, E_hat] = exact_alm_lrr_l1v2(D, A, lambda, tol, maxIter,display) 2 | 3 | % Aug 2013 4 | % This matlab code implements the Exact ALM algorithm for 5 | % min_{Z,E} |Z|_* + lambda |E|_1 s.t. D = AZ + E 6 | % 7 | % D - m x n matrix of observations/data (required input) 8 | % A - m x k matrix of the dictionary (required input) 9 | 10 | % lambda - weight on sparse error term in the cost function 11 | % 12 | % tol - tolerance for stopping criterion. 13 | % - DEFAULT 1e-7 if omitted or -1. 14 | % 15 | % maxIter - maximum number of iterations 16 | % - DEFAULT 1000, if omitted or -1. 17 | % 18 | [m n] = size(D); 19 | k = size(A,2); 20 | n_max = max(m,n); 21 | 22 | 23 | if nargin < 3 || isempty(lambda) 24 | lambda = 1 / sqrt(n_max); 25 | end 26 | 27 | if nargin < 4 || isempty(tol) 28 | tol = 1e-7; 29 | end 30 | 31 | if nargin < 5 || isempty(maxIter) 32 | maxIter = 1000; 33 | end 34 | 35 | if nargin<6 || isempty(display) 36 | display = false; 37 | end 38 | 39 | maxIter_primal = 10000; 40 | % initialize 41 | Y = sign(D); 42 | norm_two = norm(Y,2); 43 | norm_inf = norm( Y(:), inf) / lambda; 44 | dual_norm = max(norm_two, norm_inf); 45 | Y = Y / dual_norm; 46 | 47 | W = zeros(k,n); 48 | 49 | Z_hat = zeros(k,n); 50 | E_hat = zeros(m,n); 51 | %parameters 52 | dnorm = norm(D, 'fro'); 53 | tolProj1 = 1e-6 * dnorm; 54 | 55 | anorm = norm(A,2); 56 | tolProj2 = 1e-6 * dnorm/anorm; 57 | 58 | mu = .5/norm_two; % this one can be tuned 59 | rho = 6; % this one can be tuned 60 | 61 | %pre-computation 62 | if m>=k 63 | inv_ata = inv(eye(k) + A'*A); 64 | else 65 | inv_ata = eye(k) - A'/(eye(m)+A*A')*A; 66 | end 67 | 68 | iter = 0; 69 | while iter < maxIter 70 | iter = iter + 1; 71 | 72 | % solve the primal problem by alternative projection 73 | primal_iter = 0; 74 | 75 | while primal_iter < maxIter_primal 76 | primal_iter = primal_iter + 1; 77 | temp_Z = Z_hat; 78 | temp_E = E_hat; 79 | 80 | %update J 81 | temp = temp_Z + W/mu; 82 | [U S V] = svd(temp, 'econ'); 83 | 84 | diagS = diag(S); 85 | svp = length(find(diagS > 1/mu)); 86 | diagS = max(0,diagS - 1/mu); 87 | 88 | if svp < 0.5 %svp = 0 89 | svp = 1; 90 | end 91 | J_hat = U(:,1:svp)*diag(diagS(1:svp))*V(:,1:svp)'; 92 | 93 | % update Z 94 | temp = J_hat + A'*(D - temp_E) + (A'*Y-W)/mu; 95 | Z_hat = inv_ata*temp; 96 | 97 | %update E 98 | temp = D - A*Z_hat + Y/mu; 99 | E_hat = max(0,temp - lambda/mu) + min(0, temp + lambda/mu); 100 | 101 | if norm(E_hat - temp_E, 'fro') < tolProj1 && norm(Z_hat - temp_Z)0))... 116 | ', stopCriterion ' num2str(stopCriterion)]); 117 | end 118 | 119 | if stopCriterion < tol 120 | break; 121 | end 122 | 123 | 124 | end 125 | 126 | end 127 | 128 | 129 | 130 | -------------------------------------------------------------------------------- /Algorithm/LRR_code/exact_alm_lrr_l21v2.m: -------------------------------------------------------------------------------- 1 | function [Z_hat, E_hat] = exact_alm_lrr_l21v2(D, A, lambda, tol, maxIter,display) 2 | 3 | % Aug 2013 4 | % This matlab code implements the Exact ALM algorithm for 5 | % min_{Z,E} |Z|_* + lambda |E|_2,1 s.t. D = AZ + E 6 | % 7 | % D - m x n matrix of observations/data (required input) 8 | % A - m x k matrix of the dictionary (required input) 9 | 10 | % lambda - weight on sparse error term in the cost function 11 | % 12 | % tol - tolerance for stopping criterion. 13 | % - DEFAULT 1e-7 if omitted or -1. 14 | % 15 | % maxIter - maximum number of iterations 16 | % - DEFAULT 1000, if omitted or -1. 17 | % 18 | [m n] = size(D); 19 | k = size(A,2); 20 | 21 | 22 | if nargin < 4 || isempty(tol) 23 | tol = 1e-7; 24 | end 25 | 26 | if nargin < 5 || isempty(maxIter) 27 | maxIter = 1000; 28 | end 29 | 30 | if nargin<6 || isempty(display) 31 | display = false; 32 | end 33 | 34 | maxIter_primal = 10000; 35 | % initialize 36 | Y = sign(D); 37 | norm_two = norm(Y,2); 38 | norm_inf = norm( Y(:), inf) / lambda; 39 | dual_norm = max(norm_two, norm_inf); 40 | Y = Y / dual_norm; 41 | 42 | W = zeros(k,n); 43 | 44 | Z_hat = zeros(k,n); 45 | E_hat = zeros(m,n); 46 | %parameters 47 | dnorm = norm(D, 'fro'); 48 | tolProj1 = 1e-6 * dnorm; 49 | 50 | anorm = norm(A,2); 51 | tolProj2 = 1e-6 * dnorm/anorm; 52 | 53 | mu = .5/norm_two; % this one can be tuned 54 | rho = 6; % this one can be tuned 55 | 56 | %pre-computation 57 | if m>=k 58 | inv_ata = inv(eye(k) + A'*A); 59 | else 60 | inv_ata = eye(k) - A'/(eye(m)+A*A')*A; 61 | end 62 | 63 | iter = 0; 64 | while iter < maxIter 65 | iter = iter + 1; 66 | 67 | % solve the primal problem by alternative projection 68 | primal_iter = 0; 69 | 70 | while primal_iter < maxIter_primal 71 | primal_iter = primal_iter + 1; 72 | temp_Z = Z_hat; 73 | temp_E = E_hat; 74 | 75 | %update J 76 | temp = temp_Z + W/mu; 77 | [U S V] = svd(temp, 'econ'); 78 | 79 | diagS = diag(S); 80 | svp = length(find(diagS > 1/mu)); 81 | diagS = max(0,diagS - 1/mu); 82 | 83 | if svp < 0.5 %svp = 0 84 | svp = 1; 85 | end 86 | J_hat = U(:,1:svp)*diag(diagS(1:svp))*V(:,1:svp)'; 87 | 88 | % update Z 89 | temp = J_hat + A'*(D - temp_E) + (A'*Y-W)/mu; 90 | Z_hat = inv_ata*temp; 91 | 92 | %update E 93 | temp = D - A*Z_hat + Y/mu; 94 | E_hat = solve_l1l2(temp, lambda/mu); 95 | 96 | if norm(E_hat - temp_E, 'fro') < tolProj1 && norm(Z_hat - temp_Z)0))... 111 | ', stopCriterion ' num2str(stopCriterion)]); 112 | end 113 | 114 | if stopCriterion < tol 115 | break; 116 | end 117 | 118 | 119 | end 120 | 121 | end 122 | 123 | 124 | 125 | -------------------------------------------------------------------------------- /Algorithm/LRR_code/inexact_alm_lrr_l1.m: -------------------------------------------------------------------------------- 1 | function [Z,E] = inexact_alm_lrr_l1(X,A,lambda,display) 2 | % This routine uses Inexact ALM algorithm to solve the following nuclear-norm optimization problem: 3 | % min |Z|_*+lambda*|E|_1 4 | % s.t., X = AZ+E 5 | % inputs: 6 | % X -- D*N data matrix, D is the data dimension, and N is the number 7 | % of data vectors. 8 | % A -- D*M matrix of a dictionary, M is the size of the dictionary 9 | 10 | if nargin<4 11 | display = false; 12 | end 13 | 14 | tol = 1e-8; 15 | maxIter = 1e6; 16 | [d n] = size(X); 17 | m = size(A,2); 18 | rho = 1.1; 19 | max_mu = 1e10; 20 | mu = 1e-6; 21 | atx = A'*X; 22 | inv_a = inv(A'*A+eye(m)); 23 | %% Initializing optimization variables 24 | % intialize 25 | J = zeros(m,n); 26 | Z = zeros(m,n); 27 | E = sparse(d,n); 28 | 29 | Y1 = zeros(d,n); 30 | Y2 = zeros(m,n); 31 | %% Start main loop 32 | iter = 0; 33 | if display 34 | disp(['initial,rank=' num2str(rank(Z))]); 35 | end 36 | while iter1/mu)); 43 | if svp>=1 44 | sigma = sigma(1:svp)-1/mu; 45 | else 46 | svp = 1; 47 | sigma = 0; 48 | end 49 | J = U(:,1:svp)*diag(sigma)*V(:,1:svp)'; 50 | 51 | %udpate Z 52 | Z = inv_a*(atx-A'*E+J+(A'*Y1-Y2)/mu); 53 | 54 | %update E 55 | xmaz = X-A*Z; 56 | temp = xmaz+Y1/mu; 57 | E = max(0,temp - lambda/mu)+min(0,temp + lambda/mu); 58 | 59 | leq1 = xmaz-E; 60 | leq2 = Z-J; 61 | stopC = max(max(max(abs(leq1))),max(max(abs(leq2)))); 62 | if display && (iter==1 || mod(iter,50)==0 || stopC1/mu)); 44 | if svp>=1 45 | sigma = sigma(1:svp)-1/mu; 46 | else 47 | svp = 1; 48 | sigma = 0; 49 | end 50 | J = U(:,1:svp)*diag(sigma)*V(:,1:svp)'; 51 | %udpate Z 52 | Z = inv_a*(atx-A'*E+J+(A'*Y1-Y2)/mu); 53 | %update E 54 | xmaz = X-A*Z; 55 | temp = xmaz+Y1/mu; 56 | E = solve_l1l2(temp,lambda/mu); 57 | 58 | leq1 = xmaz-E; 59 | leq2 = Z-J; 60 | stopC = max(max(max(abs(leq1))),max(max(abs(leq2)))); 61 | if display && (iter==1 || mod(iter,50)==0 || stopC 1/mu)); 36 | diagS = max(0,S - 1/mu); 37 | J = U*diagS*V'; 38 | % if svp < 0.5 %svp = 0 39 | % svp = 1; 40 | % end 41 | % J = U(:,1:svp)*diag(diagS(1:svp))*V(:,1:svp)'; 42 | 43 | % update Z 44 | T1 = eye(n) + X1; 45 | T2 = X'*Y1 - Y2; 46 | Z = T1\(X1 - X'*E + J + T2/mu); 47 | 48 | % update E 49 | Q = X - X*Z + Y1/mu; 50 | E = shk(Q,lambda/mu); 51 | 52 | % update Y1 ,Y2 53 | Y1 = Y1 + mu*(X - X*Z - E); 54 | Y2 = Y2 + mu*(Z - J); 55 | % update mu 56 | mu = min(rho*mu,mu_max); 57 | 58 | % check convergence 59 | del(1) = norm(X-X*Z-E,inf); 60 | del(2) = norm(Z-J,inf); 61 | if max(del) < epsilon 62 | break 63 | else 64 | fprintf('Iter %3d: del_Z=%5.3e del_J=%5.3e \n', k, del(1), del(2)); 65 | 66 | 67 | 68 | end 69 | end -------------------------------------------------------------------------------- /Algorithm/LRR_code/solve_E.m: -------------------------------------------------------------------------------- 1 | function E = solve_E(Q,v) 2 | [m,n] = size(Q); 3 | for i = 1:n 4 | if v < norm(Q(:,i)) 5 | E(:,i) = (norm(Q(:,i)) - v)/norm(Q(:,i))*Q(:,i); 6 | else 7 | E(:,i) = zeros(m,1); 8 | end 9 | end -------------------------------------------------------------------------------- /Algorithm/LRR_code/solve_l1l2.m: -------------------------------------------------------------------------------- 1 | function [E] = solve_l1l2(W,lambda) 2 | n = size(W,2); 3 | E = W; 4 | for i=1:n 5 | E(:,i) = solve_l2(W(:,i),lambda); 6 | end 7 | end 8 | 9 | function [x] = solve_l2(w,lambda) 10 | % min lambda |x|_2 + |x-w|_2^2 11 | nw = norm(w); 12 | if nw>lambda 13 | x = (nw-lambda)*w/nw; 14 | else 15 | x = zeros(length(w),1); 16 | end 17 | end -------------------------------------------------------------------------------- /Algorithm/LRR_code/solve_lrr.m: -------------------------------------------------------------------------------- 1 | function [Z,E] = solve_lrr(X,A,lambda,reg,alm_type,display) 2 | % Aug 2013 3 | % This routine solves the following nuclear-norm optimization problem, 4 | % min |Z|_*+lambda*|E|_L 5 | % s.t., X = AZ+E 6 | % inputs: 7 | % X -- D*N data matrix, D is the data dimension, and N is the number 8 | % of data vectors. 9 | % A -- D*M matrix of a dictionary, M is the size of the dictionary 10 | % lambda -- parameter 11 | % reg -- the norm chosen for characterizing E, 12 | % -- reg=0 (default), use the l21-norm 13 | % -- reg=1 (or ther values except 0), use the l1-norm 14 | % alm_type -- 0 (default) use the exact ALM strategy 15 | % -- 1 use the inexact ALM strategy 16 | % 17 | if nargin < 6 || isempty(display) 18 | display = false; 19 | end 20 | if nargin<5 || isempty(alm_type) 21 | alm_type = 0 ; 22 | end 23 | 24 | if nargin<4 || isempty(reg) 25 | reg = 0; 26 | end 27 | 28 | Q = orth(A'); 29 | B = A*Q; 30 | 31 | if reg==0 32 | if alm_type ==0 33 | [Z,E] = exact_alm_lrr_l21v2(X,B,lambda,[],[],display); 34 | else 35 | [Z,E] = inexact_alm_lrr_l21(X,B,lambda,display); 36 | end 37 | else 38 | if alm_type == 0 39 | [Z,E] = exact_alm_lrr_l1v2(X,B,lambda,[],[],display); 40 | else 41 | [Z,E] = inexact_alm_lrr_l1(X,B,lambda,display); 42 | end 43 | end 44 | Z = Q*Z; -------------------------------------------------------------------------------- /Algorithm/LRSR_code/lrsr.m: -------------------------------------------------------------------------------- 1 | function [X,E,obj,err,iter] = lrsr(A,B,para,opts) 2 | 3 | % Solve the Low-Rank and Sparse Representation (LRSR) minimization problem by M-ADMM 4 | % 5 | % min_{X,E} ||X||_*+lambda1*||X||_1+lambda2*loss(E), s.t. A=BX+E 6 | % loss(E) = ||E||_1 or 0.5*||E||_F^2 or ||E||_{2,1} 7 | % --------------------------------------------- 8 | % Input: 9 | % A - d*na matrix 10 | % B - d*nb matrix 11 | % lambda1 - >0, parameter 12 | % lambda2 - >0, parameter 13 | % opts - Structure value in Matlab. The fields are 14 | % opts.loss - 'l1': loss(E) = ||E||_1 15 | % 'l2': loss(E) = 0.5*||E||_F^2 16 | % 'l21' (default): loss(E) = ||E||_{2,1} 17 | % opts.tol - termination tolerance 18 | % opts.max_iter - maximum number of iterations 19 | % opts.mu - stepsize for dual variable updating in ADMM 20 | % opts.max_mu - maximum stepsize 21 | % opts.rho - rho>=1, ratio used to increase mu 22 | % opts.DEBUG - 0 or 1 23 | % 24 | % Output: 25 | % X - nb*na matrix 26 | % E - d*na matrix 27 | % obj - objective function value 28 | % err - residual 29 | % iter - number of iterations 30 | % 31 | % version 1.0 - 18/06/2016 32 | % 33 | % Written by Canyi Lu (canyilu@gmail.com) 34 | % 35 | lambda1 = para.lambda1; 36 | lambda2 = para.lambda2; 37 | tol = 1e-8; 38 | max_iter = 500; 39 | rho = 1.1; 40 | mu = 1e-4; 41 | max_mu = 1e10; 42 | DEBUG = 0; 43 | loss = 'l21'; 44 | 45 | if ~exist('opts', 'var') 46 | opts = []; 47 | end 48 | if isfield(opts, 'loss'); loss = opts.loss; end 49 | if isfield(opts, 'tol'); tol = opts.tol; end 50 | if isfield(opts, 'max_iter'); max_iter = opts.max_iter; end 51 | if isfield(opts, 'rho'); rho = opts.rho; end 52 | if isfield(opts, 'mu'); mu = opts.mu; end 53 | if isfield(opts, 'max_mu'); max_mu = opts.max_mu; end 54 | if isfield(opts, 'DEBUG'); DEBUG = opts.DEBUG; end 55 | 56 | 57 | [d,na] = size(A); 58 | [~,nb] = size(B); 59 | 60 | X = zeros(nb,na); 61 | E = zeros(d,na); 62 | Z = X; 63 | J = X; 64 | 65 | Y1 = E; 66 | Y2 = X; 67 | Y3 = X; 68 | BtB = B'*B; 69 | BtA = B'*A; 70 | I = eye(nb); 71 | invBtBI = (BtB+2*I)\I; 72 | 73 | iter = 0; 74 | for iter = 1 : max_iter 75 | Xk = X; 76 | Zk = Z; 77 | Ek = E; 78 | Jk = J; 79 | % first super block {Z,J,E} 80 | [Z,nuclearnormZ] = prox_nuclear(X+Y2/mu,1/mu); 81 | J = prox_l1(X+Y3/mu,lambda1/mu); 82 | J = J - diag(diag(J)); 83 | if strcmp(loss,'l1') 84 | E = prox_l1(A-B*X+Y1/mu,lambda2/mu); 85 | elseif strcmp(loss,'l21') 86 | E = prox_l21(A-B*X+Y1/mu,lambda2/mu); 87 | elseif strcmp(loss,'l2') 88 | E = mu*(A-B*X+Y1/mu)/(lambda2+mu); 89 | else 90 | error('not supported loss function'); 91 | end 92 | % second super block {X} 93 | X = invBtBI*(B'*(Y1/mu-E)+BtA-(Y2+Y3)/mu+Z+J); 94 | 95 | dY1 = A-B*X-E; 96 | dY2 = X-Z; 97 | dY3 = X-J; 98 | chgX = max(max(abs(Xk-X))); 99 | chgE = max(max(abs(Ek-E))); 100 | chgZ = max(max(abs(Zk-Z))); 101 | chgJ = max(max(abs(Jk-J))); 102 | chg = max([chgX chgE chgZ chgJ max(abs(dY1(:))) max(abs(dY2(:))) max(abs(dY3(:)))]); 103 | if DEBUG 104 | if iter == 1 || mod(iter, 10) == 0 105 | obj = nuclearnormZ+lambda1*norm(J(:),1)+lambda2*comp_loss(E,loss); 106 | err = sqrt(norm(dY1,'fro')^2+norm(dY2,'fro')^2+norm(dY3,'fro')^2); 107 | disp(['iter ' num2str(iter) ', mu=' num2str(mu) ... 108 | ', obj=' num2str(obj) ', err=' num2str(err)]); 109 | end 110 | end 111 | 112 | if chg < tol 113 | break; 114 | end 115 | Y1 = Y1 + mu*dY1; 116 | Y2 = Y2 + mu*dY2; 117 | mu = min(rho*mu,max_mu); 118 | end 119 | obj = nuclearnormZ+lambda1*norm(J(:),1)+lambda2*comp_loss(E,loss); 120 | err = sqrt(norm(dY1,'fro')^2+norm(dY2,'fro')^2+norm(dY3,'fro')^2); 121 | 122 | 123 | function out = comp_loss(E,normtype) 124 | 125 | switch normtype 126 | case 'l1' 127 | out = norm(E(:),1); 128 | case 'l21' 129 | out = 0; 130 | for i = 1 : size(E,2) 131 | out = out + norm(E(:,i)); 132 | end 133 | case 'l2' 134 | out = 0.5*norm(E,'fro')^2; 135 | end -------------------------------------------------------------------------------- /Algorithm/LSR_code/LSR_FS/Data/YaleB.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Virgeo/Graph-based-subspsce-clustering/705aaedc2ae2476c3f6e67e87e92bcc736e0934c/Algorithm/LSR_code/LSR_FS/Data/YaleB.mat -------------------------------------------------------------------------------- /Algorithm/LSR_code/LSR_FS/Experiment_FS.m: -------------------------------------------------------------------------------- 1 | % Face clustering on the Extended Yale B database by using LSR in 2 | 3 | % Can-Yi Lu, Hai Min, Zhong-Qiu Zhao, Lin Zhu, De-Shuang Huang and Shuicheng Yan. 4 | % Robust and Efficient Subspace Segmentation via Least Squares Regression, 5 | % European Conference on Computer Vision (ECCV), 2012. 6 | 7 | %-------------------------------------------------------------------------- 8 | % Copyright @ Can-Yi Lu, 2012 9 | %-------------------------------------------------------------------------- 10 | 11 | 12 | clear ; 13 | close all; 14 | currentpath = cd ; 15 | AddedPath = genpath( currentpath ) ; 16 | addpath( AddedPath ) ; 17 | fprintf('\n\n************************************** %s *************************************\n' , datestr(now) ); 18 | fprintf( [ mfilename(currentpath) ' Begins.\n' ] ) ; 19 | fprintf( [ mfilename(currentpath) ' is going, please wait...\n' ] ) ; 20 | 21 | %% Data YaleB 22 | load YaleB % load YaleB dataset 23 | nCluster = 10 ; % number of subspace, 5 or 10 used in our paper 24 | num = nCluster * 64 ; % number of data used for subspace segmentation 25 | fea = fea(:,1:num) ; 26 | gnd = gnd(:,1:num) ; 27 | redDim = nCluster * 6 ; 28 | 29 | 30 | 31 | %% PCA Projection 32 | [ eigvector , eigvalue ] = PCA( fea ) ; 33 | maxDim = length(eigvalue); 34 | fea = eigvector' * fea ; 35 | 36 | % normalize 37 | for i = 1 : size(fea,2) 38 | fea(:,i) = fea(:,i) /norm(fea(:,i)) ; 39 | end 40 | 41 | 42 | %% Subspace segmentation methods 43 | SegmentationMethod = 'LSR1' ; % LSR1 by (16) in our paper 44 | % SegmentationMethod = 'LSR2' ; % LSR2 by (18) in our paper 45 | 46 | 47 | 48 | %% Parameter 49 | 50 | switch nCluster 51 | case 5 52 | para = [0.4] * ones(1,20) ; 53 | case 10 54 | para = [0.004 ] * ones(1,20) ; 55 | end 56 | 57 | 58 | 59 | %% Output results 60 | fid = 1 ; % output to the screen 61 | fprintf( fid , ['Function = ' mfilename(currentpath) '.m\n'] ) ; 62 | fprintf( fid , 'Data = %s, nCluster = %d\n' , 'YaleB' , nCluster ) ; 63 | fprintf( fid , 'SegmentationMethod = %s\n' , SegmentationMethod ) ; 64 | num_para = length( para ) ; 65 | num_redDim = length( redDim ) ; 66 | fprintf( fid , 'para =' ) ; 67 | for i = 1 : num_para 68 | fprintf( fid , '\t%5f' , para(i) ) ; 69 | end 70 | fprintf( fid , '\n' ) ; 71 | 72 | %% Subspace segmentation 73 | Accuracy = zeros( num_redDim , num_para ) ; 74 | for i = 1 : num_redDim 75 | d = redDim( i ) ; 76 | fprintf( 'd = %d', d ) ; 77 | Yfea = fea(1:d,:) ; 78 | for j = 1 : num_para 79 | p = para( j ) ; 80 | Accuracy(i,j) = SubspaceSegmentation( SegmentationMethod , Yfea , gnd , p ) ; 81 | fprintf( fid , '\t%.3f ' , Accuracy(i,j)*100 ) ; 82 | end 83 | fprintf('\n') ; 84 | end 85 | 86 | 87 | %% output 88 | fprintf('\n\n'); 89 | fprintf( fid , 'para =' ) ; 90 | for i = 1 : length(para) 91 | fprintf( fid , '\t%5f' , para(i) ) ; 92 | end 93 | fprintf( fid , '\n' ) ; 94 | for i = 1 : length(redDim) 95 | d = redDim( i ) ; 96 | fprintf( 'd = %d', d ) ; 97 | for j = 1 : length(para) 98 | fprintf( fid , '\t%.3f ' , Accuracy(i,j)*100 ) ; 99 | end 100 | fprintf('\n') ; 101 | end 102 | 103 | [maxa ind] = max( Accuracy*100 ) 104 | maxpara = para(ind) 105 | maxAcc = max( max(Accuracy*100) ) 106 | 107 | 108 | 109 | 110 | 111 | % rmpath( genpath(currentpath) ) ; 112 | -------------------------------------------------------------------------------- /Algorithm/LSR_code/LSR_FS/LSR/LSR1.m: -------------------------------------------------------------------------------- 1 | function Z = LSR1( X , lambda ) 2 | 3 | %-------------------------------------------------------------------------- 4 | % Copyright @ Can-Yi Lu, 2012 5 | %-------------------------------------------------------------------------- 6 | 7 | % Input 8 | % X Data matrix, dim * num 9 | % lambda parameter, lambda>0 10 | 11 | 12 | % Output the solution to the following problem: 13 | % min ||X-XZ||_F^2+lambda||Z||_F^2 14 | % s.t. diag(Z)=0 15 | 16 | % Z num * num 17 | 18 | if nargin < 2 19 | lambda = 0.001 ; 20 | end 21 | [dim,num] = size(X) ; 22 | 23 | 24 | % for i = 1 : num 25 | % X(:,i) = X(:,i) / norm(X(:,i)) ; 26 | % end 27 | 28 | 29 | I = eye(num) ; 30 | invX = I / (X'*X+lambda*I) ; 31 | Z = zeros( num , num ) ; 32 | for i = 1 : num 33 | Z(:,i) = invX(:,i) / invX(i,i) ; 34 | Z(i,i) = 0 ; 35 | end 36 | Z = -1 * Z ; -------------------------------------------------------------------------------- /Algorithm/LSR_code/LSR_FS/LSR/LSR2.m: -------------------------------------------------------------------------------- 1 | function Z = LSR2( X , lambda ) 2 | 3 | %-------------------------------------------------------------------------- 4 | % Copyright @ Can-Yi Lu, 2012 5 | %-------------------------------------------------------------------------- 6 | 7 | % Input 8 | % X Data matrix, dim * num 9 | % lambda parameter, lambda>0 10 | 11 | 12 | % Output the solution to the following problem: 13 | % min ||X-XZ||_F^2+lambda||Z||_F^2 14 | 15 | % Z num * num 16 | 17 | 18 | if nargin < 2 19 | lambda = 0.004 ; 20 | end 21 | [dim,num] = size(X) ; 22 | 23 | 24 | % for i = 1 : num 25 | % X(:,i) = X(:,i) / norm(X(:,i)) ; 26 | % end 27 | 28 | 29 | I = lambda * eye(num) ; 30 | Z = (X'*X+I) \ X' * X ; -------------------------------------------------------------------------------- /Algorithm/LSR_code/LSR_FS/PCA.m: -------------------------------------------------------------------------------- 1 | function [eigvector, eigvalue, elapse] = PCA(data, options) 2 | 3 | %% PCA Principal Component Analysis 4 | % 5 | % Usage: 6 | % [eigvector, eigvalue] = PCA(data, options) 7 | % [eigvector, eigvalue] = PCA(data) 8 | % 9 | % Input: 10 | % data - Data matrix. Each row vector of fea is a data point. 11 | % 12 | % options.ReducedDim - The dimensionality of the reduced subspace. If 0, 13 | % all the dimensions will be kept. 14 | % Default is 0. 15 | % 16 | % Output: 17 | % eigvector - Each column is an embedding function, for a new 18 | % data point (row vector) x, y = x*eigvector 19 | % will be the embedding result of x. 20 | % eigvalue - The sorted eigvalue of PCA eigen-problem. 21 | % 22 | % Examples: 23 | % fea = rand(7,10); 24 | % [eigvector,eigvalue] = PCA(fea,4); 25 | % Y = fea*eigvector; 26 | % 27 | % version 2.2 --Feb/2009 28 | % version 2.1 --June/2007 29 | % version 2.0 --May/2007 30 | % version 1.1 --Feb/2006 31 | % version 1.0 --April/2004 32 | % 33 | % Written by Deng Cai (dengcai2 AT cs.uiuc.edu) 34 | % 35 | 36 | data = data' ; 37 | 38 | if (~exist('options','var')) 39 | options = []; 40 | end 41 | 42 | ReducedDim = 0; 43 | if isfield(options,'ReducedDim') 44 | ReducedDim = options.ReducedDim; 45 | end 46 | 47 | 48 | [nSmp,nFea] = size(data); 49 | if (ReducedDim > nFea) || (ReducedDim <=0) 50 | ReducedDim = nFea; 51 | end 52 | 53 | tmp_T = cputime; 54 | 55 | 56 | if issparse(data) 57 | data = full(data); 58 | end 59 | sampleMean = mean(data,1); 60 | data = (data - repmat(sampleMean,nSmp,1)); 61 | 62 | 63 | 64 | if nFea/nSmp > 1.0713 65 | % This is an efficient method which computes the eigvectors of 66 | % of A*A^T (instead of A^T*A) first, and then convert them back to 67 | % the eigenvectors of A^T*A. 68 | ddata = data*data'; 69 | ddata = max(ddata, ddata'); 70 | 71 | dimMatrix = size(ddata,2); 72 | if dimMatrix > 1000 && ReducedDim < dimMatrix/10 % using eigs to speed up! 73 | option = struct('disp',0); 74 | [eigvector, eigvalue] = eigs(ddata,ReducedDim,'la',option); 75 | eigvalue = diag(eigvalue); 76 | else 77 | [eigvector, eigvalue] = eig(ddata); 78 | eigvalue = diag(eigvalue); 79 | 80 | [junk, index] = sort(-eigvalue); 81 | eigvalue = eigvalue(index); 82 | eigvector = eigvector(:, index); 83 | end 84 | 85 | clear ddata; 86 | 87 | maxEigValue = max(abs(eigvalue)); 88 | eigIdx = find(abs(eigvalue)/maxEigValue < 1e-12); 89 | eigvalue (eigIdx) = []; 90 | eigvector (:,eigIdx) = []; 91 | 92 | eigvector = data'*eigvector; % Eigenvectors of A^T*A 93 | eigvector = eigvector*diag(1./(sum(eigvector.^2).^0.5)); % Normalization 94 | else 95 | ddata = data'*data; 96 | ddata = max(ddata, ddata'); 97 | 98 | dimMatrix = size(ddata,2); 99 | if dimMatrix > 1000 & ReducedDim < dimMatrix/10 % using eigs to speed up! 100 | option = struct('disp',0); 101 | [eigvector, eigvalue] = eigs(ddata,ReducedDim,'la',option); 102 | eigvalue = diag(eigvalue); 103 | else 104 | [eigvector, eigvalue] = eig(ddata); 105 | eigvalue = diag(eigvalue); 106 | 107 | [junk, index] = sort(-eigvalue); 108 | eigvalue = eigvalue(index); 109 | eigvector = eigvector(:, index); 110 | end 111 | 112 | clear ddata; 113 | maxEigValue = max(abs(eigvalue)); 114 | eigIdx = find(abs(eigvalue)/maxEigValue < 1e-12); 115 | eigvalue (eigIdx) = []; 116 | eigvector (:,eigIdx) = []; 117 | end 118 | 119 | 120 | if ReducedDim < length(eigvalue) 121 | eigvalue = eigvalue(1:ReducedDim); 122 | eigvector = eigvector(:, 1:ReducedDim); 123 | end 124 | 125 | 126 | if isfield(options,'PCARatio') 127 | sumEig = sum(eigvalue); 128 | sumEig = sumEig*options.PCARatio; 129 | sumNow = 0; 130 | for idx = 1:length(eigvalue) 131 | sumNow = sumNow + eigvalue(idx); 132 | if sumNow >= sumEig 133 | break; 134 | end 135 | end 136 | eigvector = eigvector(:,1:idx); 137 | end 138 | 139 | elapse = cputime - tmp_T; 140 | -------------------------------------------------------------------------------- /Algorithm/LSR_code/LSR_FS/SubspaceSegmentation.m: -------------------------------------------------------------------------------- 1 | function [acc,L] = SubspaceSegmentation( SegmentatiomMethod , X , gnd , para ) 2 | 3 | switch SegmentatiomMethod 4 | 5 | case 'LSR1' 6 | L = LSR1( X , para ) ; 7 | 8 | case 'LSR2' 9 | L = LSR2( X , para ) ; 10 | end 11 | 12 | 13 | for i = 1 : size(L,2) 14 | L(:,i) = L(:,i) / max(abs(L(:,i))) ; 15 | end 16 | 17 | nCluster = length( unique( gnd ) ) ; 18 | Z = ( abs(L) + abs(L') ) / 2 ; 19 | idx = clu_ncut(Z,nCluster) ; 20 | acc = compacc(idx,gnd) ; 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | % for i = 1 : size(L,2) 45 | % Z(:,i) = Z(:,i) / max(max(Z)) ; 46 | % end 47 | % % Z(Z>0.01) = 1 ; 48 | % imshow(1-Z) 49 | 50 | 51 | 52 | % figure 53 | % for i = 1 : size(L,2) 54 | % L(:,i) = L(:,i) / max(L(:,i)) ; 55 | % end 56 | % imshow(1-L) 57 | 58 | 59 | -------------------------------------------------------------------------------- /Algorithm/LSR_code/LSR_FS/clu_ncut.m: -------------------------------------------------------------------------------- 1 | function [idx] = clu_ncut(L,K) 2 | % this routine groups the data X into K subspaces by NCut 3 | % inputs: 4 | % L -- an N*N affinity matrix, N is the number of data points 5 | % K -- the number of subpaces (i.e., clusters) 6 | L = (L + L')/2; 7 | D = diag(1./sqrt(sum(L,2))); 8 | L = D*L*D; 9 | [U,S,V] = svd(L); 10 | 11 | V = U(:,1:K); 12 | V = D*V; 13 | 14 | idx = kmeans(V,K,'emptyaction','singleton','replicates',10,'display','off'); 15 | idx = idx'; -------------------------------------------------------------------------------- /Algorithm/LSR_code/LSR_FS/compacc.m: -------------------------------------------------------------------------------- 1 | function [acc] = compacc(idx1,idx0) 2 | %inputs: 3 | % idx1 -- the clustering results 4 | % idx0 -- the groudtruth clustering results 5 | %outputs: 6 | % acc -- segmentation accuracy (or classification accuracy) 7 | uids = unique(idx1); 8 | idx = idx1; 9 | for i=1:length(uids) 10 | uid = uids(i); 11 | inds = abs(idx1-uid)<0.1; 12 | vids = idx0(inds); 13 | uvids = unique(vids); 14 | vf = 0; 15 | for j=1:length(uvids) 16 | vfj = sum(abs(vids-uvids(j))<0.1); 17 | if vfj>vf; 18 | vid = uvids(j); 19 | vf = vfj; 20 | end 21 | end 22 | idx(inds) = vid; 23 | end 24 | acc = sum(abs(idx-idx0)<0.1)/length(idx0); -------------------------------------------------------------------------------- /Algorithm/LSR_code/LSR_FS/read me.txt: -------------------------------------------------------------------------------- 1 | Copyright @Can-Yi Lu, 2012 2 | 3 | This code is about the Least Squares Regression (LSR) method for subspace segmentation for our work: 4 | Can-Yi Lu, Hai Min, Zhong-Qiu Zhao, Lin Zhu, De-Shuang Huang and Shuicheng Yan. Robust and Efficient Subspace Segmentation via Least Squares Regression, European Conference on Computer Vision (ECCV), 2012. 5 | 6 | The code is provided for research purposes only. 7 | 8 | For face clustering on the Extended Yale B database, run Experiment_YaleB.m directly! 9 | 10 | Please contact Can-Yi Lu (canyilu@gmail.com) for questions about the code. 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /Algorithm/LSR_code/LSR_MS/Experiment_MS.m: -------------------------------------------------------------------------------- 1 | % Motion segmentation on the Hopkins 155 database by using LSR in 2 | 3 | % Can-Yi Lu, Hai Min, Zhong-Qiu Zhao, Lin Zhu, De-Shuang Huang and Shuicheng Yan. 4 | % Robust and Efficient Subspace Segmentation via Least Squares Regression, 5 | % European Conference on Computer Vision (ECCV), 2012. 6 | 7 | %-------------------------------------------------------------------------- 8 | % Copyright @ Can-Yi Lu, 2012 9 | %-------------------------------------------------------------------------- 10 | 11 | clear ; 12 | % close all; 13 | cd '/Users/CWG/Documents/m.text/Hopkins155/'; 14 | currentpath = '/Users/CWG/Documents/m.text/SSC_motion_face/'; 15 | AddedPath = genpath( currentpath ) ; 16 | addpath( AddedPath ) ; 17 | fprintf('\n\n************************************** %s *************************************\n' , datestr(now) ); 18 | fprintf( [ mfilename(currentpath) ' Begins.\n' ] ) ; 19 | fprintf( [ mfilename(currentpath) ' is going, please wait...\n' ] ) ; 20 | 21 | %% reduced dimension 22 | ProjRank = 12 ; 23 | 24 | seqs = dir; 25 | % Get rid of the two directories: "." and ".." 26 | seq3 = seqs(3:end); 27 | % Save the data loaded in struct "data" 28 | data = struct('ProjX', {}, 'name',{}, 'ids',{}); 29 | 30 | 31 | for i=1:length(seq3) 32 | fname = seq3(i).name; 33 | fdir = [cd '/' fname]; 34 | if isdir(fdir) 35 | datai = load([fdir '/' fname '_truth.mat']); 36 | id = length(data)+1; 37 | % the true group numbers 38 | data(id).ids = datai.s; 39 | % file name 40 | data(id).name = lower(fname); 41 | % X is the motion sequence 42 | X = reshape(permute(datai.x(1:2,:,:),[1 3 2]), 2*datai.frames, datai.points); 43 | 44 | % PCA projection 45 | [ eigvector , eigvalue ] = PCA( X ) ; 46 | ProjX = eigvector(:,1:ProjRank)' * X ; 47 | data(id).ProjX = [ProjX ; ones(1,size(ProjX,2)) ] ; 48 | end 49 | end 50 | clear seq3; 51 | 52 | 53 | %% Subspace segmentation methods 54 | SegmentationMethod = 'LSR1' ; % LSR1 by (16) in our paper 55 | % SegmentationMethod = 'LSR2' ; % LSR2 by (18) in our paper 56 | 57 | 58 | %% Parameter 59 | switch SegmentationMethod 60 | case 'LSR1' 61 | para = 4.8*1e-3 ; 62 | case 'LSR2' 63 | para = 4.6*1e-3 ; 64 | end 65 | 66 | 67 | %% 68 | errs = zeros(length(data),1); 69 | for i = 1 : 156 % 156 sequences 70 | ProjX = data(i).ProjX ; 71 | gnd = data(i).ids' ; 72 | K = length( unique( gnd ) ) ; 73 | errs(i) = SubspaceSegmentation( SegmentationMethod , ProjX , gnd , para ) ; 74 | errs(i) = 100 - 100 * errs(i) ; 75 | fprintf('seq %d\t %f\n', i , errs(i) ) ; 76 | end 77 | fprintf('\n') ; 78 | 79 | 80 | %% 81 | err_mean = mean(errs) ; 82 | err_max = max(errs) ; 83 | err_min = min(errs) ; 84 | err_median = median(errs) ; 85 | err_std = std(errs) ; 86 | 87 | para 88 | disp(['max = ' num2str(max(errs)) ',min=' num2str(min(errs)) ... 89 | ',median=' num2str(median(errs)) ',mean=' num2str(mean(errs)) ',std=' num2str(std(errs))] ); 90 | 91 | 92 | 93 | 94 | 95 | -------------------------------------------------------------------------------- /Algorithm/LSR_code/LSR_MS/LSR/LSR1.m: -------------------------------------------------------------------------------- 1 | function Coeff = LSR1( X , lambda ) 2 | 3 | %-------------------------------------------------------------------------- 4 | % Copyright @ Can-Yi Lu, 2012 5 | %-------------------------------------------------------------------------- 6 | 7 | % Input 8 | % X Data matrix, dim * num 9 | % lambda parameter, lambda>0 10 | 11 | 12 | % Output the solution to the following problem: 13 | % min ||X-XZ||_F^2+lambda||Z||_F^2 14 | % s.t. diag(Z)=0 15 | 16 | % Z num * num 17 | 18 | if nargin < 2 19 | lambda = 0.001 ; 20 | end 21 | [dim,num] = size(X) ; 22 | 23 | 24 | % for i = 1 : num 25 | % X(:,i) = X(:,i) / norm(X(:,i)) ; 26 | % end 27 | 28 | 29 | I = eye(num) ; 30 | invX = I / (X'*X+lambda*I) ; 31 | Coeff = zeros( num , num ) ; 32 | for i = 1 : num 33 | Coeff(:,i) = invX(:,i) / invX(i,i) ; 34 | Coeff(i,i) = 0 ; 35 | end 36 | Coeff = -1 * Coeff ; -------------------------------------------------------------------------------- /Algorithm/LSR_code/LSR_MS/LSR/LSR2.m: -------------------------------------------------------------------------------- 1 | function Z = LSR2( X , lambda ) 2 | 3 | %-------------------------------------------------------------------------- 4 | % Copyright @ Can-Yi Lu, 2012 5 | %-------------------------------------------------------------------------- 6 | 7 | % Input 8 | % X Data matrix, dim * num 9 | % lambda parameter, lambda>0 10 | 11 | 12 | % Output the solution to the following problem: 13 | % min ||X-XZ||_F^2+lambda||Z||_F^2 14 | 15 | % Z num * num 16 | 17 | 18 | if nargin < 2 19 | lambda = 0.004 ; 20 | end 21 | [dim,num] = size(X) ; 22 | 23 | 24 | % for i = 1 : num 25 | % X(:,i) = X(:,i) / norm(X(:,i)) ; 26 | % end 27 | 28 | 29 | I = lambda * eye(num) ; 30 | Z = (X'*X+I) \ X' * X ; -------------------------------------------------------------------------------- /Algorithm/LSR_code/LSR_MS/PCA.m: -------------------------------------------------------------------------------- 1 | function [eigvector, eigvalue, elapse] = PCA(data, options) 2 | 3 | %% PCA Principal Component Analysis 4 | % 5 | % Usage: 6 | % [eigvector, eigvalue] = PCA(data, options) 7 | % [eigvector, eigvalue] = PCA(data) 8 | % 9 | % Input: 10 | % data - Data matrix. Each row vector of fea is a data point. 11 | % 12 | % options.ReducedDim - The dimensionality of the reduced subspace. If 0, 13 | % all the dimensions will be kept. 14 | % Default is 0. 15 | % 16 | % Output: 17 | % eigvector - Each column is an embedding function, for a new 18 | % data point (row vector) x, y = x*eigvector 19 | % will be the embedding result of x. 20 | % eigvalue - The sorted eigvalue of PCA eigen-problem. 21 | % 22 | % Examples: 23 | % fea = rand(7,10); 24 | % [eigvector,eigvalue] = PCA(fea,4); 25 | % Y = fea*eigvector; 26 | % 27 | % version 2.2 --Feb/2009 28 | % version 2.1 --June/2007 29 | % version 2.0 --May/2007 30 | % version 1.1 --Feb/2006 31 | % version 1.0 --April/2004 32 | % 33 | % Written by Deng Cai (dengcai2 AT cs.uiuc.edu) 34 | % 35 | 36 | data = data' ; 37 | 38 | if (~exist('options','var')) 39 | options = []; 40 | end 41 | 42 | ReducedDim = 0; 43 | if isfield(options,'ReducedDim') 44 | ReducedDim = options.ReducedDim; 45 | end 46 | 47 | 48 | [nSmp,nFea] = size(data); 49 | if (ReducedDim > nFea) || (ReducedDim <=0) 50 | ReducedDim = nFea; 51 | end 52 | 53 | tmp_T = cputime; 54 | 55 | 56 | if issparse(data) 57 | data = full(data); 58 | end 59 | sampleMean = mean(data,1); 60 | data = (data - repmat(sampleMean,nSmp,1)); 61 | 62 | 63 | 64 | if nFea/nSmp > 1.0713 65 | % This is an efficient method which computes the eigvectors of 66 | % of A*A^T (instead of A^T*A) first, and then convert them back to 67 | % the eigenvectors of A^T*A. 68 | ddata = data*data'; 69 | ddata = max(ddata, ddata'); 70 | 71 | dimMatrix = size(ddata,2); 72 | if dimMatrix > 1000 && ReducedDim < dimMatrix/10 % using eigs to speed up! 73 | option = struct('disp',0); 74 | [eigvector, eigvalue] = eigs(ddata,ReducedDim,'la',option); 75 | eigvalue = diag(eigvalue); 76 | else 77 | [eigvector, eigvalue] = eig(ddata); 78 | eigvalue = diag(eigvalue); 79 | 80 | [junk, index] = sort(-eigvalue); 81 | eigvalue = eigvalue(index); 82 | eigvector = eigvector(:, index); 83 | end 84 | 85 | clear ddata; 86 | 87 | maxEigValue = max(abs(eigvalue)); 88 | eigIdx = find(abs(eigvalue)/maxEigValue < 1e-12); 89 | eigvalue (eigIdx) = []; 90 | eigvector (:,eigIdx) = []; 91 | 92 | eigvector = data'*eigvector; % Eigenvectors of A^T*A 93 | eigvector = eigvector*diag(1./(sum(eigvector.^2).^0.5)); % Normalization 94 | else 95 | ddata = data'*data; 96 | ddata = max(ddata, ddata'); 97 | 98 | dimMatrix = size(ddata,2); 99 | if dimMatrix > 1000 & ReducedDim < dimMatrix/10 % using eigs to speed up! 100 | option = struct('disp',0); 101 | [eigvector, eigvalue] = eigs(ddata,ReducedDim,'la',option); 102 | eigvalue = diag(eigvalue); 103 | else 104 | [eigvector, eigvalue] = eig(ddata); 105 | eigvalue = diag(eigvalue); 106 | 107 | [junk, index] = sort(-eigvalue); 108 | eigvalue = eigvalue(index); 109 | eigvector = eigvector(:, index); 110 | end 111 | 112 | clear ddata; 113 | maxEigValue = max(abs(eigvalue)); 114 | eigIdx = find(abs(eigvalue)/maxEigValue < 1e-12); 115 | eigvalue (eigIdx) = []; 116 | eigvector (:,eigIdx) = []; 117 | end 118 | 119 | 120 | if ReducedDim < length(eigvalue) 121 | eigvalue = eigvalue(1:ReducedDim); 122 | eigvector = eigvector(:, 1:ReducedDim); 123 | end 124 | 125 | 126 | if isfield(options,'PCARatio') 127 | sumEig = sum(eigvalue); 128 | sumEig = sumEig*options.PCARatio; 129 | sumNow = 0; 130 | for idx = 1:length(eigvalue) 131 | sumNow = sumNow + eigvalue(idx); 132 | if sumNow >= sumEig 133 | break; 134 | end 135 | end 136 | eigvector = eigvector(:,1:idx); 137 | end 138 | 139 | elapse = cputime - tmp_T; 140 | -------------------------------------------------------------------------------- /Algorithm/LSR_code/LSR_MS/SubspaceSegmentation.m: -------------------------------------------------------------------------------- 1 | function acc = SubspaceSegmentation( SegmentatiomMethod , X , gnd , para ) 2 | 3 | switch SegmentatiomMethod 4 | 5 | case 'LSR1' 6 | L = LSR1( X , para ) ; 7 | 8 | case 'LSR2' 9 | L = LSR2( X , para ) ; 10 | end 11 | 12 | nCluster = length( unique( gnd ) ) ; 13 | Z = ( abs(L) + abs(L') ) / 2 ; 14 | idx = clu_ncut(Z,nCluster) ; 15 | acc = compacc(idx,gnd) ; 16 | -------------------------------------------------------------------------------- /Algorithm/LSR_code/LSR_MS/clu_ncut.m: -------------------------------------------------------------------------------- 1 | function [idx] = clu_ncut(L,K) 2 | % this routine groups the data X into K subspaces by NCut 3 | % inputs: 4 | % L -- an N*N affinity matrix, N is the number of data points 5 | % K -- the number of subpaces (i.e., clusters) 6 | L = (L + L')/2; 7 | D = diag(1./sqrt(sum(L,2))); 8 | L = D*L*D; 9 | [U,S,V] = svd(L); 10 | 11 | V = U(:,1:K); 12 | V = D*V; 13 | 14 | idx = kmeans(V,K,'emptyaction','singleton','replicates',10,'display','off'); 15 | idx = idx'; -------------------------------------------------------------------------------- /Algorithm/LSR_code/LSR_MS/compacc.m: -------------------------------------------------------------------------------- 1 | function [acc] = compacc(idx1,idx0) 2 | %inputs: 3 | % idx1 -- the clustering results 4 | % idx0 -- the groudtruth clustering results 5 | %outputs: 6 | % acc -- segmentation accuracy (or classification accuracy) 7 | uids = unique(idx1); 8 | idx = idx1; 9 | for i=1:length(uids) 10 | uid = uids(i); 11 | inds = abs(idx1-uid)<0.1; 12 | vids = idx0(inds); 13 | uvids = unique(vids); 14 | vf = 0; 15 | for j=1:length(uvids) 16 | vfj = sum(abs(vids-uvids(j))<0.1); 17 | if vfj>vf; 18 | vid = uvids(j); 19 | vf = vfj; 20 | end 21 | end 22 | idx(inds) = vid; 23 | end 24 | acc = sum(abs(idx-idx0)<0.1)/length(idx0); -------------------------------------------------------------------------------- /Algorithm/LSR_code/LSR_MS/read me.txt: -------------------------------------------------------------------------------- 1 | Copyright @Can-Yi Lu, 2012 2 | 3 | This code is about the Least Squares Regression (LSR) method for subspace segmentation for our work: 4 | Can-Yi Lu, Hai Min, Zhong-Qiu Zhao, Lin Zhu, De-Shuang Huang and Shuicheng Yan. Robust and Efficient Subspace Segmentation via Least Squares Regression, European Conference on Computer Vision (ECCV), 2012. 5 | 6 | The code is provided for research purposes only. 7 | 8 | For motion segmentation on the Hopkins 155 database, one should first download the motion data from http://www.vision.jhu.edu/data/hopkins155/, and release the data in the .\Data subfolder. Then run Experiment_MS.m directly! 9 | 10 | Please contact Can-Yi Lu (canyilu@gmail.com) for questions about the code. 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /Algorithm/LatLRR_code/clu_ncut.m: -------------------------------------------------------------------------------- 1 | function [idx] = clu_ncut(L,K) 2 | % this routine groups the data X into K subspaces by NCut 3 | % inputs: 4 | % L -- an N*N affinity matrix, N is the number of data points 5 | % K -- the number of subpaces (i.e., clusters) 6 | L = (L + L')/2; 7 | D = diag(1./sqrt(sum(L,2))); 8 | L = D*L*D; 9 | [U,S,V] = svd(L); 10 | 11 | V = U(:,1:K); 12 | V = D*V; 13 | idx = kmeans(V,K,'emptyaction','singleton','replicates',10,'display','off'); 14 | idx = idx'; -------------------------------------------------------------------------------- /Algorithm/LatLRR_code/latlrr_face_recog.m: -------------------------------------------------------------------------------- 1 | function [] = latlrr_face_recog() 2 | data = load('yaleball_reD.mat'); 3 | data = data.obj; 4 | 5 | %solve latlrr 6 | [Z,L,E] = solve_latlrr(data.Xtrain,0.4,1,1.5); 7 | 8 | ytrain = L*data.Xtrain; 9 | ytest = L*data.Xtest; 10 | 11 | ks = 1:2:5; 12 | for i=1:length(ks) 13 | k = ks(i); 14 | ypred = knnclassify(ytest',ytrain',data.traincids',k); 15 | acc = sum(abs(ypred'-data.testcids)<0.1)/length(ypred); 16 | disp(['acc(' num2str(k) 'nn)=' num2str(acc)]); 17 | end -------------------------------------------------------------------------------- /Algorithm/LatLRR_code/latlrr_motion_seg.m: -------------------------------------------------------------------------------- 1 | function [] = latlrr_motion_seg() 2 | tic; 3 | datadir = '../datas/hop155'; 4 | seqs = dir(datadir); 5 | seq3 = seqs(3:end); 6 | %% load the data 7 | data = struct('X',{},'name',{},'ids',{}); 8 | for i=1:length(seq3) 9 | fname = seq3(i).name; 10 | fdir = [datadir '/' fname]; 11 | if isdir(fdir) 12 | datai = load([fdir '/' fname '_truth.mat']); 13 | id = length(data)+1; 14 | data(id).ids = datai.s; 15 | data(id).name = lower(fname); 16 | X = reshape(permute(datai.x(1:2,:,:),[1 3 2]),2*datai.frames,datai.points); 17 | data(id).X = [X;ones(1,size(X,2))]; 18 | end 19 | end 20 | clear seq3; 21 | %% preprocessing 22 | rand('state', 1212498032853324); 23 | randn('state', 121243456980328533249450); 24 | for i=1:length(data) 25 | X = data(i).X; 26 | [d n] = size(X); 27 | noise = randn(d,n); 28 | noise = 0.03*noise.*abs(X); 29 | inds = rand(d,n)<10/100; 30 | X(inds) = X(inds)+noise(inds); 31 | data(i).X = X; 32 | end 33 | %% segmentation 34 | errs = zeros(length(data),1); 35 | for i=1:length(data) 36 | X = data(i).X; 37 | gnd = data(i).ids; K = max(gnd); 38 | if abs(K-2)>0.1 && abs(K-3)>0.1 39 | id = i; % the discarded sequqnce 40 | end 41 | % perfrom latlrr 42 | Z = solve_latlrr(X,1.4); 43 | 44 | % 45 | disp('post processing ... ...'); 46 | Z = rpcapsd(Z,0.5); 47 | 48 | % refining Z 49 | [U,S,V] = svd(Z); 50 | S = diag(S); 51 | r = min(4*K+1,sum(S>1e-3*S(1))); 52 | S = S(1:r); 53 | U = U(:,1:r)*diag(sqrt(S)); 54 | U = normr(U); 55 | Z = U*U';Z=abs(Z);L = Z.^4.5; 56 | 57 | % spectral clustering 58 | L = (L + L')/2; 59 | D = diag(1./sqrt(sum(L,2))); 60 | L = D*L*D; 61 | [U,S,V] = svd(L); 62 | 63 | V = U(:,1:K); 64 | V = D*V; 65 | idx = kmeans(V,K,'emptyaction','singleton','replicates',20,'display','off'); 66 | 67 | % display 68 | err = missclassGroups(idx,gnd,K)/length(idx); 69 | disp(['seq ' num2str(i) ',err=' num2str(err)]); 70 | errs(i) = err; 71 | end 72 | disp('results of all 156 sequences:'); 73 | disp(['max = ' num2str(max(errs)) ',min=' num2str(min(errs)) ... 74 | ',median=' num2str(median(errs)) ',mean=' num2str(mean(errs)) ',std=' num2str(std(errs))] ); 75 | 76 | errs = errs([1:id-1,id+1:end]); 77 | disp('results of all 155 sequences:'); 78 | disp(['max = ' num2str(max(errs)) ',min=' num2str(min(errs)) ... 79 | ',median=' num2str(median(errs)) ',mean=' num2str(mean(errs)) ',std=' num2str(std(errs))] ); 80 | 81 | toc; 82 | -------------------------------------------------------------------------------- /Algorithm/LatLRR_code/missclassGroups.m: -------------------------------------------------------------------------------- 1 | %-------------------------------------------------------------------------- 2 | % [miss,index] = missclass(Segmentation,RefSegmentation,ngroups) 3 | % Computes the number of missclassified points in the vector Segmentation. 4 | % Segmentation: 1 by sum(npoints) or sum(ngroups) by 1 vector containing 5 | % the label for each group, ranging from 1 to n 6 | % npoints: 1 by ngroups or ngroups by 1 vector containing the number of 7 | % points in each group. 8 | % ngroups: number of groups 9 | %-------------------------------------------------------------------------- 10 | % Copyright @ Ehsan Elhamifar, 2010 11 | %-------------------------------------------------------------------------- 12 | 13 | 14 | function [miss,index] = missclassGroups(Segmentation,RefSegmentation,ngroups) 15 | if(size(RefSegmentation,2)==1) 16 | RefSegmentation=RefSegmentation'; 17 | end 18 | if(size(Segmentation,2)==1) 19 | Segmentation=Segmentation'; 20 | end 21 | Permutations = perms(1:ngroups); 22 | miss = zeros(size(Permutations,1),size(Segmentation,1)); 23 | for k=1:size(Segmentation,1) 24 | for j=1:size(Permutations,1) 25 | miss(j,k) = sum(abs(Segmentation(k,:)-Permutations(j,RefSegmentation))>0.1); 26 | end 27 | end 28 | 29 | [miss,temp] = min(miss,[],1); 30 | index = Permutations(temp,:); 31 | -------------------------------------------------------------------------------- /Algorithm/LatLRR_code/rpcapsd.m: -------------------------------------------------------------------------------- 1 | function [Z,E] = rpcapsd(X,lambda,rho,display) 2 | %NSPCODE Summary of this function goes here 3 | % Detailed explanation goes here 4 | % min |Z|_*+lambda*|E|_1 5 | % s.t., X = Z+E 6 | % Z is psd 7 | if nargin<4 8 | display = false; 9 | end 10 | if nargin<3 11 | rho = 2; 12 | end 13 | if nargin<2 14 | lambda = 1; 15 | end 16 | tol = 1e-6; 17 | maxIter = 1e6; 18 | [d n] = size(X); 19 | max_mu = 1e10; 20 | mu = 1e-6; 21 | %% Initializing optimization variables 22 | % intialize 23 | E = sparse(d,n); 24 | Z = zeros(d,n); 25 | 26 | Y = zeros(d,n); 27 | %% Start main loop 28 | iter = 0; 29 | if display 30 | disp(['initial,rank=' num2str(rank(Z))]); 31 | end 32 | while iter1/mu; 41 | if sum(inds)>0 42 | D = diag(D(inds)-1/mu); 43 | Z = U(:,inds)*D*U(:,inds)'; 44 | else 45 | Z = 0; 46 | end 47 | rZ = sum(inds); 48 | 49 | temp = X-Z+Y/mu; 50 | E = max(0,temp - lambda/mu)+min(0,temp + lambda/mu); 51 | 52 | leq = X-Z-E; 53 | stopC = max(max(abs(leq))); 54 | if display && (iter==1 || mod(iter,50)==0 || stopC1/mu)); 46 | if svp>=1 47 | sigma = sigma(1:svp)-1/mu; 48 | else 49 | svp = 1; 50 | sigma = 0; 51 | end 52 | J = U(:,1:svp)*diag(sigma)*V(:,1:svp)'; 53 | rZ = svp; %rank(J); 54 | 55 | %update S 56 | temp = L + Y3/mu; 57 | [U,sigma,V] = svd(temp,'econ'); 58 | sigma = diag(sigma); 59 | svp = length(find(sigma>alpha/mu)); 60 | if svp>=1 61 | sigma = sigma(1:svp)-alpha/mu; 62 | else 63 | svp = 1; 64 | sigma = 0; 65 | end 66 | S = U(:,1:svp)*diag(sigma)*V(:,1:svp)'; 67 | rL = svp; %rank(S); 68 | 69 | %udpate Z 70 | Z = inv_ata*(A'*X-A'*L*B-A'*E+J+(A'*Y1-Y2)/mu); 71 | 72 | %update L 73 | L = (X*B'-A*Z*B'-E*B'+S+(Y1*B'-Y3)/mu)*inv_bbt; 74 | 75 | %update E 76 | temp = X-A*Z-L*B+Y1/mu; 77 | E = max(0,temp - beta/mu)+min(0,temp + beta/mu); 78 | 79 | %update the multiplies 80 | leq1 = X-A*Z-L*B-E; 81 | leq2 = Z-J; 82 | leq3 = L-S; 83 | stopC = max(max(max(abs(leq1))),max(max(abs(leq2)))); 84 | stopC = max(max(max(abs(leq3))),stopC); 85 | % if iter==1 || mod(iter,50)==0 || stopC=0, 1'x=1 8 | % 9 | 10 | if nargin < 2 11 | k = 1; 12 | end 13 | 14 | ft=1; 15 | n = length(v); 16 | 17 | v0 = v-mean(v) + k/n; 18 | %vmax = max(v0); 19 | vmin = min(v0); 20 | if vmin < 0 21 | f = 1; 22 | lambda_m = 0; 23 | while abs(f) > 10^-10 24 | v1 = v0 - lambda_m; 25 | posidx = v1>0; 26 | npos = sum(posidx); 27 | g = -npos; 28 | f = sum(v1(posidx)) - k; 29 | lambda_m = lambda_m - f/g; 30 | ft=ft+1; 31 | if ft > 100 32 | x = max(v1,0); 33 | break; 34 | end 35 | end 36 | x = max(v1,0); 37 | 38 | else 39 | x = v0; 40 | end -------------------------------------------------------------------------------- /Algorithm/RSS_code/funs/L2_distance_1.m: -------------------------------------------------------------------------------- 1 | % compute squared Euclidean distance 2 | % ||A-B||^2 = ||A||^2 + ||B||^2 - 2*A'*B 3 | function d = L2_distance_1(a,b) 4 | % a,b: two matrices. each column is a data 5 | % d: distance matrix of a and b 6 | 7 | 8 | 9 | if (size(a,1) == 1) 10 | a = [a; zeros(1,size(a,2))]; 11 | b = [b; zeros(1,size(b,2))]; 12 | end 13 | 14 | aa=sum(a.*a); bb=sum(b.*b); ab=a'*b; 15 | d = repmat(aa',[1 size(bb,2)]) + repmat(bb,[size(aa,2) 1]) - 2*ab; 16 | 17 | d = real(d); 18 | d = max(d,0); 19 | 20 | % % force 0 on the diagonal? 21 | % if (df==1) 22 | % d = d.*(1-eye(size(d))); 23 | % end 24 | -------------------------------------------------------------------------------- /Algorithm/RSS_code/funs/SubClu_SimR.p: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Virgeo/Graph-based-subspsce-clustering/705aaedc2ae2476c3f6e67e87e92bcc736e0934c/Algorithm/RSS_code/funs/SubClu_SimR.p -------------------------------------------------------------------------------- /Algorithm/RSS_code/funs/clu_ncut.m: -------------------------------------------------------------------------------- 1 | function [idx] = clu_ncut(L,K) 2 | % this routine groups the data X into K subspaces by NCut 3 | % inputs: 4 | % L -- an N*N affinity matrix, N is the number of data points 5 | % K -- the number of subpaces (i.e., clusters) 6 | L = (L + L')/2; 7 | D = diag(1./sqrt(sum(L,2))); 8 | L = D*L*D; 9 | [U,S,V] = svd(L); 10 | 11 | V = U(:,1:K); 12 | V = D*V; 13 | 14 | idx = kmeans(V,K,'emptyaction','singleton','replicates',20,'display','off'); 15 | idx = idx'; -------------------------------------------------------------------------------- /Algorithm/RSS_code/funs/compacc.m: -------------------------------------------------------------------------------- 1 | function [acc] = compacc(idx1,idx0) 2 | %inputs: 3 | % idx1 -- the clustering results 4 | % idx0 -- the groudtruth clustering results 5 | %outputs: 6 | % acc -- segmentation accuracy (or classification accuracy) 7 | uids = unique(idx1); 8 | idx = idx1; 9 | for i=1:length(uids) 10 | uid = uids(i); 11 | inds = abs(idx1-uid)<0.1; 12 | vids = idx0(inds); 13 | uvids = unique(vids); 14 | vf = 0; 15 | for j=1:length(uvids) 16 | vfj = sum(abs(vids-uvids(j))<0.1); 17 | if vfj>vf; 18 | vid = uvids(j); 19 | vf = vfj; 20 | end 21 | end 22 | idx(inds) = vid; 23 | end 24 | acc = sum(abs(idx-idx0)<0.1)/length(idx0); -------------------------------------------------------------------------------- /Algorithm/RSS_code/funs/computeACC.m: -------------------------------------------------------------------------------- 1 | function accAvg = computeACC(T,gnd,rep) 2 | 3 | nCluster = length( unique( gnd ) ) ; 4 | Z = ( abs(T) + abs(T') ) / 2 ; 5 | accAvg=0; 6 | for j = 1 : rep 7 | idx = clu_ncut(Z,nCluster) ; 8 | acc = compacc(idx,gnd); 9 | accAvg = accAvg+acc; 10 | end 11 | accAvg = accAvg/rep; 12 | 13 | end -------------------------------------------------------------------------------- /Algorithm/S3C_code/ADMM_StrSSC.m: -------------------------------------------------------------------------------- 1 | % ADMM_StrSSC.m 2 | % Decsription: This code is, modified from Esan's SSC code, for solving the Structured SSC which is an iterated re-weighted scheme for the subspace 3 | % segmentation. 4 | %-------------------------------------------------------------------------- 5 | % This function takes a DxN matrix of N data points in a D-dimensional 6 | % space and returns a NxN coefficient matrix of the sparse representation 7 | % of each data point in terms of the rest of the points 8 | % Y: DxN data matrix 9 | % affine: if true then enforce the affine constraint 10 | % thr1: stopping threshold for the coefficient error ||Z-C|| 11 | % thr2: stopping threshold for the linear system error ||Y-YZ|| 12 | % maxIter: maximum number of iterations of ADMM 13 | % C2: NxN sparse coefficient matrix 14 | %-------------------------------------------------------------------------- 15 | % Copyright @ Ehsan Elhamifar, 2012 16 | %-------------------------------------------------------------------------- 17 | % 18 | % Modified by Chunguang Li 19 | % Date: Jan 21, 2014. 20 | 21 | function C2 = ADMM_StrSSC(Y, alpha, affine,outliers, Theta, gamma0, nu, maxIter, Z, thr) 22 | if (nargin < 2) 23 | % default regularizarion parameters 24 | alpha = 800; 25 | 26 | end 27 | if (nargin < 3) 28 | % default subspaces are linear 29 | affine = false; 30 | end 31 | if (nargin < 4) 32 | % default subspaces are linear 33 | outliers = false; 34 | end 35 | if (nargin < 5) 36 | % default regularizarion parameters 37 | Theta = zeros(size(Y, 2)); 38 | end 39 | if (nargin < 6) 40 | gamma0 =0.1; 41 | end 42 | if (nargin < 7) 43 | nu =1; 44 | end 45 | if (nargin < 8) 46 | % default maximum number of iterations of ADMM 47 | maxIter = 200; 48 | end 49 | if (nargin < 9) 50 | % default maximum number of iterations of ADMM 51 | Z = zeros(size(Y, 2)); 52 | end 53 | if (nargin < 10) 54 | % default coefficient error threshold to stop ADMM 55 | % default linear system error threshold to stop ADMM 56 | thr = 2*10^-4; 57 | end 58 | 59 | if (~outliers) 60 | 61 | %% ADMM_Lasso_weighted 62 | if (length(alpha) == 1) 63 | alpha1 = alpha(1); 64 | alpha2 = alpha(1); 65 | elseif (length(alpha) == 2) 66 | alpha1 = alpha(1); 67 | alpha2 = alpha(2); 68 | end 69 | 70 | if (length(thr) == 1) 71 | thr1 = thr(1); 72 | thr2 = thr(1); 73 | elseif (length(thr) == 2) 74 | thr1 = thr(1); 75 | thr2 = thr(2); 76 | end 77 | 78 | N = size(Y,2); 79 | 80 | % setting penalty parameters for the ADMM 81 | mu1 = alpha1 * 1/computeLambda_mat(Y); 82 | mu2 = alpha2 * 1; 83 | if (~affine) 84 | % initialization 85 | A = inv(mu1*(Y'*Y)+mu2*eye(N)); 86 | %C1 = zeros(N,N); 87 | C1 =Z; 88 | Lambda2 = zeros(N,N); 89 | err1 = 10*thr1; err2 = 10*thr2; 90 | i = 1; 91 | % ADMM iterations 92 | while ( err1(i) > thr1 && i < maxIter ) 93 | % updating Z 94 | Z = A * (mu1*(Y'*Y)+mu2*(C1-Lambda2/mu2)); 95 | Z = Z - diag(diag(Z)); 96 | % updating C 97 | % C2 = max(0,(abs(Z+Lambda2/mu2) - 1/mu2*ones(N))) .* sign(Z+Lambda2/mu2); 98 | C2 = max(0,(abs(Z+Lambda2/mu2) - 1/mu2*(ones(N)./nu+ nu*gamma0 * (1-Theta)))) .* sign(Z+Lambda2/mu2); 99 | C2 = C2 - diag(diag(C2)); 100 | % updating Lagrange multipliers 101 | Lambda2 = Lambda2 + mu2 * (Z - C2); 102 | % computing errors 103 | err1(i+1) = errorCoef(Z,C2); 104 | err2(i+1) = errorLinSys(Y,Z); 105 | % 106 | C1 = C2; 107 | i = i + 1; 108 | end 109 | fprintf('err1: %2.4f, err2: %2.4f, iter: %3.0f \n',err1(end),err2(end),i); 110 | else 111 | % initialization 112 | A = inv(mu1*(Y'*Y)+mu2*eye(N)+mu2*ones(N,N)); 113 | %C1 = zeros(N,N); 114 | C1 =Z; 115 | Lambda2 = zeros(N,N); 116 | lambda3 = zeros(1,N); 117 | err1 = 10*thr1; err2 = 10*thr2; err3 = 10*thr1; 118 | i = 1; 119 | % ADMM iterations 120 | while ( (err1(i) > thr1 || err3(i) > thr1) && i < maxIter ) 121 | % updating Z 122 | Z = A * (mu1*(Y'*Y)+mu2*(C1-Lambda2/mu2)+mu2*ones(N,1)*(ones(1,N)-lambda3/mu2)); 123 | Z = Z - diag(diag(Z)); 124 | % updating C 125 | %C2 = max(0,(abs(Z+Lambda2/mu2) - 1/mu2* ones(N))) .* sign(Z+Lambda2/mu2); 126 | %C2 = max(0,(abs(Z+Lambda2/mu2) - 1/mu2*(ones(N) + nu*gamma0 *(1-Theta)))) .* sign(Z+Lambda2/mu2); 127 | C2 = max(0,(abs(Z+Lambda2/mu2) - 1/mu2*(ones(N)./nu+ nu* gamma0 *(1-Theta)))) .* sign(Z+Lambda2/mu2); 128 | C2 = C2 - diag(diag(C2)); 129 | % updating Lagrange multipliers 130 | Lambda2 = Lambda2 + mu2 * (Z - C2); 131 | lambda3 = lambda3 + mu2 * (ones(1,N)*Z - ones(1,N)); 132 | % computing errors 133 | err1(i+1) = errorCoef(Z,C2); 134 | err2(i+1) = errorLinSys(Y,Z); 135 | err3(i+1) = errorCoef(ones(1,N)*Z,ones(1,N)); 136 | % 137 | C1 = C2; 138 | i = i + 1; 139 | end 140 | fprintf('err1: %2.4f, err2: %2.4f, err3: %2.4f, iter: %3.0f \n',err1(end),err2(end),err3(end),i); 141 | end 142 | 143 | else 144 | 145 | %% ADMM_SSC_outliers_weighted_tune1 146 | if (length(alpha) == 1) 147 | alpha1 = alpha(1); 148 | alpha2 = alpha(1); 149 | alpha3 = alpha(1); 150 | elseif (length(alpha) == 2) 151 | alpha1 = alpha(1); 152 | alpha2 = alpha(2); 153 | alpha3 = alpha(2); 154 | elseif (length(alpha) == 3) 155 | alpha1 = alpha(1); 156 | alpha2 = alpha(2); 157 | alpha3 = alpha(3); 158 | end 159 | 160 | if (length(thr) == 1) 161 | thr1 = thr(1); 162 | thr2 = thr(1); 163 | elseif (length(thr) == 2) 164 | thr1 = thr(1); 165 | thr2 = thr(2); 166 | end 167 | 168 | [D,N] = size(Y); 169 | 170 | gamma = alpha3 / norm(Y,1); 171 | P = [Y eye(D)/gamma]; 172 | 173 | % setting penalty parameters for the ADMM 174 | mu1 = alpha1 * 1/computeLambda_mat(Y, Y); 175 | mu2 = alpha2 * 1; 176 | %mu3 =alpha1 * 1/computeLambda_mat(Y, eye(D)/gamma); 177 | 178 | if (~affine) 179 | % initialization 180 | A = inv(mu1*(P'*P)+mu2*eye(N+D)); 181 | %C1 = zeros(N+D,N); 182 | C1 =[Z; zeros(D, N)]; 183 | Lambda1 = zeros(D,N); 184 | Lambda2 = zeros(N+D,N); 185 | err1 = 10*thr1; err2 = 10*thr2; 186 | i = 1; 187 | % ADMM iterations 188 | while ( (err1(i) > thr1 || err2(i) > thr2) && i < maxIter ) 189 | % updating Z 190 | Z = A * (mu1*P'*(Y+Lambda1/mu1)+mu2*(C1-Lambda2/mu2)); 191 | Z(1:N,:) = Z(1:N,:) - diag(diag(Z(1:N,:))); 192 | % updating C 193 | %C2 = max(0,(abs(Z +Lambda2 /mu2) - 1/mu2* ones(N+D,N))) .* sign(Z +Lambda2 /mu2); 194 | C2(N+1:N+D,:) = max(0,(abs(Z(N+1:N+D,:)+Lambda2(N+1:N+D,:) /mu2) - 1/mu2* ones(D, N))) .* sign(Z(N+1:N+D,:)+Lambda2(N+1:N+D,:) /mu2); 195 | %C2(1:N,:) = max(0,(abs(Z(1:N,:) +Lambda2(1:N,:) /mu2) - 1/mu2*(ones(N, N) + nu*gamma0 *(1-Theta)))) .* sign(Z(1:N,:) +Lambda2(1:N,:) /mu2); 196 | C2(1:N,:) = max(0,(abs(Z(1:N,:) +Lambda2(1:N,:) /mu2) - 1/mu2*(ones(N, N)./nu+ nu*gamma0 *(1-Theta)))) .* sign(Z(1:N,:)+Lambda2(1:N,:)/mu2); 197 | C2(1:N,:) = C2(1:N,:) - diag(diag(C2(1:N,:))); 198 | % updating Lagrange multipliers 199 | Lambda1 = Lambda1 + mu1 * (Y - P * Z); 200 | Lambda2 = Lambda2 + mu2 * (Z - C2); 201 | % computing errors 202 | err1(i+1) = errorCoef(Z,C2); 203 | err2(i+1) = errorLinSys(P,Z); 204 | % 205 | C1 = C2; 206 | i = i + 1; 207 | end 208 | fprintf('err1: %2.4f, err2: %2.4f, iter: %3.0f \n',err1(end),err2(end),i); 209 | else 210 | % initialization 211 | delta = [ones(N,1);zeros(D,1)]; 212 | A = inv(mu1*(P'*P)+mu2*eye(N+D)+mu2*(delta*delta')); 213 | %C1 = zeros(N+D,N); 214 | C1 =[Z; zeros(D, N)]; 215 | Lambda1 = zeros(D,N); 216 | Lambda2 = zeros(N+D,N); 217 | lambda3 = zeros(1,N); 218 | err1 = 10*thr1; err2 = 10*thr2; err3 = 10*thr1; 219 | i = 1; 220 | % ADMM iterations 221 | while ( (err1(i) > thr1 || err2(i) > thr2 || err3(i) > thr1) && i < maxIter ) 222 | % updating Z 223 | Z = A * (mu1*P'*(Y+Lambda1/mu1)+mu2*(C1-Lambda2/mu2)+mu2*delta*(ones(1,N)-lambda3/mu2)); 224 | Z(1:N,:) = Z(1:N,:) - diag(diag(Z(1:N,:))); 225 | % updating C 226 | %C2 = max(0,(abs(Z +Lambda2 /mu2) - 1/mu2* ones(N+D,N))) .* sign(Z +Lambda2/mu2); 227 | C2(N+1:N+D,:) = max(0,(abs(Z(N+1:N+D,:)+Lambda2(N+1:N+D,:) /mu2) - 1/mu2* ones(D, N) )) .* sign(Z(N+1:N+D,:)+Lambda2(N+1:N+D,:) /mu2); 228 | C2(1:N,:) = max(0,(abs(Z(1:N,:) +Lambda2(1:N,:) /mu2) - 1/mu2*(ones(N )./nu + nu*gamma0* (1-Theta)))) .* sign(Z(1:N,:) +Lambda2(1:N,:) /mu2); 229 | %C2(1:N,:) = max(0,(abs(Z(1:N,:) +Lambda2(1:N,:) /mu2) - 1/mu2*(ones(N) + gamma0 * (1-Theta)))) .* sign(Z(1:N,:) +Lambda2(1:N,:) /mu2); 230 | C2(1:N,:) = C2(1:N,:) - diag(diag(C2(1:N,:))); 231 | % updating Lagrange multipliers 232 | Lambda1 = Lambda1 + mu1 * (Y - P * Z); 233 | Lambda2 = Lambda2 + mu2 * (Z - C2); 234 | lambda3 = lambda3 + mu2 * (delta'*Z - ones(1,N)); 235 | % computing errors 236 | err1(i+1) = errorCoef(Z,C2); 237 | err2(i+1) = errorLinSys(P,Z); 238 | err3(i+1) = errorCoef(delta'*Z,ones(1,N)); 239 | % 240 | C1 = C2; 241 | i = i + 1; 242 | end 243 | fprintf('err1: %2.4f, err2: %2.4f, err3: %2.4f, iter: %3.0f \n',err1(end),err2(end),err3(end),i); 244 | end 245 | 246 | end 247 | C2 =C2(1:N,:); -------------------------------------------------------------------------------- /Algorithm/S3C_code/BuildAdjacency.m: -------------------------------------------------------------------------------- 1 | %-------------------------------------------------------------------------- 2 | % This function takes a NxN coefficient matrix and returns a NxN adjacency 3 | % matrix by choosing the K strongest connections in the similarity graph 4 | % CMat: NxN coefficient matrix 5 | % K: number of strongest edges to keep; if K=0 use all the exiting edges 6 | % CKSym: NxN symmetric adjacency matrix 7 | %-------------------------------------------------------------------------- 8 | % Copyright @ Ehsan Elhamifar, 2012 9 | %-------------------------------------------------------------------------- 10 | 11 | 12 | function [CKSym,CAbs] = BuildAdjacency(CMat,K) 13 | 14 | if (nargin < 2) 15 | K = 0; 16 | end 17 | 18 | N = size(CMat,1); 19 | CAbs = abs(CMat); 20 | 21 | [Srt,Ind] = sort( CAbs,1,'descend' ); 22 | 23 | if (K == 0) 24 | for i = 1:N 25 | CAbs(:,i) = CAbs(:,i) ./ (CAbs(Ind(1,i),i)+eps); 26 | end 27 | else 28 | for i = 1:N 29 | for j = 1:K 30 | CAbs(Ind(j,i),i) = CAbs(Ind(j,i),i) ./ (CAbs(Ind(1,i),i)+eps); 31 | end 32 | end 33 | end 34 | 35 | CKSym = CAbs + CAbs'; -------------------------------------------------------------------------------- /Algorithm/S3C_code/DataProjection.m: -------------------------------------------------------------------------------- 1 | %-------------------------------------------------------------------------- 2 | % This function takes the D x N data matrix with columns indicating 3 | % different data points and project the D dimensional data into a r 4 | % dimensional subspace using PCA. 5 | % X: D x N matrix of N data points 6 | % r: dimension of the PCA projection, if r = 0, then no projection 7 | % Xp: r x N matrix of N projectred data points 8 | %-------------------------------------------------------------------------- 9 | % Copyright @ Ehsan Elhamifar, 2012 10 | %-------------------------------------------------------------------------- 11 | 12 | 13 | function Xp = DataProjection(X,r) 14 | 15 | if (nargin < 2) 16 | r = 0; 17 | end 18 | 19 | if (r == 0) 20 | Xp = X; 21 | else 22 | [U,~,~] = svd(X,0); 23 | Xp = U(:,1:r)' * X; 24 | end 25 | -------------------------------------------------------------------------------- /Algorithm/S3C_code/Misclassification.m: -------------------------------------------------------------------------------- 1 | %-------------------------------------------------------------------------- 2 | % This function takes the groups resulted from spectral clutsering and the 3 | % ground truth to compute the misclassification rate. 4 | % groups: [grp1,grp2,grp3] for three different forms of Spectral Clustering 5 | % s: ground truth vector 6 | % Missrate: 3x1 vector with misclassification rates of three forms of 7 | % spectral clustering 8 | %-------------------------------------------------------------------------- 9 | % Copyright @ Ehsan Elhamifar, 2012 10 | %-------------------------------------------------------------------------- 11 | 12 | 13 | function Missrate = Misclassification(groups,s) 14 | 15 | n = max(s); 16 | for i = 1:size(groups,2) 17 | Missrate(i,1) = missclassGroups( groups(:,i),s,n ) ./ length(s); 18 | end -------------------------------------------------------------------------------- /Algorithm/S3C_code/SSSC.m: -------------------------------------------------------------------------------- 1 | function [C,Theta] = SSSC(X,para) 2 | 3 | alpha = para.alpha; 4 | gamma0 = para.gamma0; 5 | nCluster = para.nCluster; 6 | 7 | %% set up regularization parameters 8 | 9 | 10 | maxIter = 150; 11 | iter_max =5; 12 | nu =1; 13 | % gamma0 =0.1; 14 | affine = 0; % e.g., 'ssc' 15 | outliers =1; 16 | % alpha =10; % 0.3 for lrr 17 | 18 | %% initialization 19 | [m,n] = size(X); 20 | C = zeros(n); 21 | 22 | Theta_old =ones(n); 23 | %% iterative procedure 24 | iter =0; 25 | while (iter < iter_max) 26 | iter = iter +1; 27 | gamma1 =gamma0; 28 | if (iter <= 1) 29 | %% This is the standard SSC when iter <=1 30 | nu =1; 31 | else 32 | %% This is for re-weighted SSC 33 | nu = nu * 1.2;%1.1, 1.2, 1.5, 34 | end 35 | C = ADMM_StrSSC(X, alpha,outliers, affine, Theta_old, gamma1, nu, maxIter, C); 36 | W = (abs(C) + abs(C'))/2; 37 | grps = SpectralClustering(W,nCluster); 38 | Theta = form_structure_matrix(grps); 39 | %% Checking stop criterion 40 | tmp =Theta - Theta_old; 41 | if (max(abs(tmp(:))) < 0.5) 42 | break; % if Q didn't change, stop the iterations. 43 | end 44 | Theta_old =Theta; 45 | end 46 | function M = form_structure_matrix(idx,n) 47 | if nargin<2 48 | n =size(idx,2); 49 | end 50 | M =zeros(n); 51 | id =unique(idx); 52 | for i =1:length(id) 53 | idx_i =find(idx == id(i)); 54 | M(idx_i,idx_i)=ones(size(idx_i,2)); 55 | end -------------------------------------------------------------------------------- /Algorithm/S3C_code/SpectralClusteringP.m: -------------------------------------------------------------------------------- 1 | % SpectralClustering.m 2 | % This is a modification of the ordinary spectral clustering which allows the initialization from previous clustering 3 | % results. 4 | % 5 | %-------------------------------------------------------------------------- 6 | % This function takes an adjacency matrix of a graph and computes the 7 | % clustering of the nodes using the spectral clustering algorithm of 8 | % Ng, Jordan and Weiss. 9 | % CMat: NxN adjacency matrix 10 | % n: number of groups for clustering 11 | % groups: N-dimensional vector containing the memberships of the N points 12 | % to the n groups obtained by spectral clustering 13 | %-------------------------------------------------------------------------- 14 | % Copyright @ Ehsan Elhamifar, 2012 15 | %-------------------------------------------------------------------------- 16 | % Modified by Chunguang Li, Nov. 7, 2014. 17 | function [groups, kerN] = SpectralClusteringP(CKSym,n, idx0,opt) 18 | if (nargin < 4) 19 | opt =0; % unnormalization for L 20 | end 21 | if nargin < 3 22 | warmstart =0; 23 | else 24 | warmstart =1; 25 | end 26 | warning off; 27 | N = size(CKSym,1); 28 | MAXiter = 1000; % Maximum number of iterations for KMeans 29 | %REPlic = 20; % Number of replications for KMeans 30 | REPlic = 20; % Number of replications for KMeans 31 | 32 | % Normalized spectral clustering according to Ng & Jordan & Weiss 33 | % using Normalized Symmetric Laplacian L = I - D^{-1/2} W D^{-1/2} 34 | if (~opt) 35 | DN = diag( 1./sqrt(sum(CKSym)+eps) ); 36 | LapN = speye(N) - DN * CKSym * DN; 37 | [~,~,vN] = svd(LapN); 38 | kerN = vN(:,N-n+1:N); 39 | for i = 1:N 40 | kerNS(i,:) = kerN(i,:) ./ norm(kerN(i,:)+eps); 41 | end 42 | else 43 | %% Unnormalized Laplacian 44 | D =diag(sum(CKSym)); 45 | Lap = D - CKSym; 46 | 47 | %% SVD 48 | [~,~,V] = svd(Lap); 49 | kerN = V(:,N-n+1:N); 50 | 51 | % %% Re-normalization 52 | % for i = 1:N 53 | % kerNS(i,:) = kerN(i,:) ./ norm(kerN(i,:)+eps); 54 | % end 55 | kerNS =kerN; 56 | end 57 | 58 | if (~warmstart) 59 | [groups] = kmeans(kerNS,n,'Start', 'sample', 'maxiter',MAXiter,'replicates',REPlic,'EmptyAction','singleton'); 60 | else 61 | [groups]= kmeans(kerNS,n,'Start', 'warmstart', 'initiallabel',idx0, 'maxiter',MAXiter,'replicates',REPlic,'EmptyAction','singleton'); 62 | end -------------------------------------------------------------------------------- /Algorithm/S3C_code/StrSSC.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Virgeo/Graph-based-subspsce-clustering/705aaedc2ae2476c3f6e67e87e92bcc736e0934c/Algorithm/S3C_code/StrSSC.m -------------------------------------------------------------------------------- /Algorithm/S3C_code/admm_S3C.m: -------------------------------------------------------------------------------- 1 | function C = admm_S3C(X,para,Theta_old) 2 | lambda = para.lambda; 3 | alpha = para.alpha; 4 | 5 | [m, n] = size(X); 6 | %% set up regularization parameters 7 | epsilon1 = 1e-6; 8 | mu = 1e-2; 9 | mu_max = 1e10; 10 | rho = 1.1; 11 | maxIter = 150; 12 | 13 | %% initialization 14 | A = zeros(n); 15 | C = zeros(n); 16 | E = zeros(m, n); 17 | Y1 = zeros(m, n); 18 | Y2 = zeros(n); 19 | X1 = X'*X; 20 | 21 | 22 | %% self-defined function 23 | shk = @(X, tau)(sign(X).*max(abs(X)-tau, 0)); 24 | %% iterative procedure 25 | iter =0; 26 | while(iter < maxIter) 27 | iter = iter +1; 28 | %% update representation C 29 | U = A + Y2/mu; 30 | C = shk(U,(1+alpha*Theta_old)/mu); 31 | C = C - diag(diag(C)); 32 | 33 | %% update A 34 | T1 = X - E - Y1/mu; 35 | A = (X1 + eye(n))\(X'*T1 + C - Y2/mu); 36 | 37 | %% update E 38 | V = X - X*A + Y1/mu; 39 | E = shk(V,lambda/mu); 40 | 41 | %% update Lagrange multipliers 42 | Y1 = Y1 + mu*(X - X*A -E); 43 | Y2 = Y2 + mu*(A - C); 44 | 45 | mu = min(mu_max, rho*mu); 46 | 47 | %% Check convergence 48 | del = norm(X - X*A -E, 'inf'); 49 | if(del < epsilon1) 50 | break 51 | else 52 | fprintf('Iter %3d: del=%5.3e \n', ... 53 | iter, del); 54 | end 55 | end 56 | -------------------------------------------------------------------------------- /Algorithm/S3C_code/compacc.m: -------------------------------------------------------------------------------- 1 | function [acc] = compacc(idx1,idx0) 2 | %inputs: 3 | % idx1 -- the clustering results 4 | % idx0 -- the groudtruth clustering results 5 | %outputs: 6 | % acc -- segmentation accuracy (or classification accuracy) 7 | uids = unique(idx1); 8 | idx = idx1; 9 | for i=1:length(uids) 10 | uid = uids(i); 11 | inds = abs(idx1-uid)<0.1; 12 | vids = idx0(inds); 13 | uvids = unique(vids); 14 | vf = 0; 15 | for j=1:length(uvids) 16 | vfj = sum(abs(vids-uvids(j))<0.1); 17 | if vfj>vf; 18 | vid = uvids(j); 19 | vf = vfj; 20 | end 21 | end 22 | idx(inds) = vid; 23 | end 24 | acc = sum(abs(idx-idx0)<0.1)/length(idx0); -------------------------------------------------------------------------------- /Algorithm/S3C_code/computeLambda_mat.m: -------------------------------------------------------------------------------- 1 | %-------------------------------------------------------------------------- 2 | % This function takes a DxN matrix of N data points in a D-dimensional 3 | % space and returns the regularization constant of the L1 norm 4 | % Y: DxN data matrix 5 | % lambda: regularization parameter for lambda*||C||_1 + 0.5 ||Y-YC||_F^2 6 | %-------------------------------------------------------------------------- 7 | % Copyright @ Ehsan Elhamifar, 2012 8 | %-------------------------------------------------------------------------- 9 | 10 | function lambda = computeLambda_mat(Y,P) 11 | 12 | if (nargin < 2) 13 | P = Y; 14 | end 15 | 16 | N = size(Y,2); 17 | T = P' * Y; 18 | T(1:N,:) = T(1:N,:) - diag(diag(T(1:N,:))); 19 | T = abs(T); 20 | lambda = min(max(T,[],1)); 21 | -------------------------------------------------------------------------------- /Algorithm/S3C_code/errorCoef.m: -------------------------------------------------------------------------------- 1 | %-------------------------------------------------------------------------- 2 | % This function computes the maximum error between elements of two 3 | % coefficient matrices 4 | % C: NxN coefficient matrix 5 | % Z: NxN coefficient matrix 6 | % err: infinite norm error between vectorized C and Z 7 | %-------------------------------------------------------------------------- 8 | % Copyright @ Ehsan Elhamifar, 2012 9 | %-------------------------------------------------------------------------- 10 | 11 | function err = errorCoef(Z,C) 12 | 13 | err = max(max( abs(Z-C) )); 14 | %err = norm(Z-C,'fro'); -------------------------------------------------------------------------------- /Algorithm/S3C_code/errorLinSys.m: -------------------------------------------------------------------------------- 1 | %-------------------------------------------------------------------------- 2 | % This function computes the maximum L2-norm error among the columns of the 3 | % residual of a linear system 4 | % Y: DxN data matrix of N data point in a D-dimensional space 5 | % Z: NxN sparse coefficient matrix 6 | % err: maximum L2-norm of the columns of Y-YZ 7 | %-------------------------------------------------------------------------- 8 | % Copyright @ Ehsan Elhamifar, 2012 9 | %-------------------------------------------------------------------------- 10 | 11 | function err = errorLinSys(P,Z) 12 | 13 | [R,N] = size(Z); 14 | if (R > N) 15 | E = P(:,N+1:end) * Z(N+1:end,:); 16 | Y = P(:,1:N); 17 | Y0 = Y - E; 18 | C = Z(1:N,:); 19 | else 20 | Y = P; 21 | Y0 = P; 22 | C = Z; 23 | end 24 | 25 | [Yn,n] = matrixNormalize(Y0); 26 | M = repmat(n,size(Y,1),1); 27 | S = Yn - Y * C ./ M; 28 | err = sqrt( max( sum( S.^2,1 ) ) ); -------------------------------------------------------------------------------- /Algorithm/S3C_code/matrixNormalize.m: -------------------------------------------------------------------------------- 1 | %-------------------------------------------------------------------------- 2 | % This function normalizes the columns of a given matrix 3 | % Y: DxN data matrix 4 | % Yn: DxN data matrix whose columns have unit Euclidean norm 5 | % n: N-dimensional vector of the norms of the columns of Y 6 | %-------------------------------------------------------------------------- 7 | % Copyright @ Ehsan Elhamifar, 2012 8 | %-------------------------------------------------------------------------- 9 | 10 | function [Yn,n] = matrixNormalize(Y) 11 | 12 | for i = 1:size(Y,2) 13 | n(i) = norm(Y(:,i)); 14 | Yn(:,i) = Y(:,i) ./ n(i); 15 | end -------------------------------------------------------------------------------- /Algorithm/S3C_code/missclassGroups.m: -------------------------------------------------------------------------------- 1 | %-------------------------------------------------------------------------- 2 | % [miss,index] = missclass(Segmentation,RefSegmentation,ngroups) 3 | % Computes the number of missclassified points in the vector Segmentation. 4 | % Segmentation: 1 by sum(npoints) or sum(ngroups) by 1 vector containing 5 | % the label for each group, ranging from 1 to n 6 | % npoints: 1 by ngroups or ngroups by 1 vector containing the number of 7 | % points in each group. 8 | % ngroups: number of groups 9 | %-------------------------------------------------------------------------- 10 | % Copyright @ Ehsan Elhamifar, 2012 11 | %-------------------------------------------------------------------------- 12 | 13 | 14 | function [miss,index] = missclassGroups(Segmentation,RefSegmentation,ngroups) 15 | 16 | Permutations = perms(1:ngroups); 17 | if(size(Segmentation,2)==1) 18 | Segmentation=Segmentation'; 19 | end 20 | miss = zeros(size(Permutations,1),size(Segmentation,1)); 21 | for k=1:size(Segmentation,1) 22 | for j=1:size(Permutations,1) 23 | miss(j,k) = sum(Segmentation(k,:)~=Permutations(j,RefSegmentation)); 24 | end 25 | end 26 | 27 | [miss,temp] = min(miss,[],1); 28 | index = Permutations(temp,:); 29 | -------------------------------------------------------------------------------- /Algorithm/S3C_code/readme.txt: -------------------------------------------------------------------------------- 1 | To run this code: 2 | 3 | 1. Need some codes of 'SSC_ADMM_v1.1'. 4 | 5 | 2. Put the modified version of 'kmean.m', which uses the previous clustering result for initialization, into the statistical toolbox to replace 'kmean.m'. 6 | 7 | Chunguang -------------------------------------------------------------------------------- /Algorithm/S3C_code/run_StrSSC_Faces.m: -------------------------------------------------------------------------------- 1 | % run_StrSSC_Faces.m 2 | % 3 | % This code is modified from Esan's SSC code. 4 | % 5 | clc; 6 | clear all 7 | close all 8 | %addpath('../lrr'); 9 | addpath('./CodefromSSC'); 10 | % addpath('../SSC_ADMM_v1.1'); 11 | 12 | load YaleBCrop025.mat 13 | load 'C:\Users\csjunxu\Desktop\SC\Datasets\YaleB_Crop.mat' 14 | results_fn =['StrSSC_Faces_tuned_gamma0_results',datestr(now,30),'.mat']; 15 | alpha = 20; 16 | gamma0 =0.1; % 0.1 for Face 17 | %lambda =0.15; % for LRR 18 | 19 | nSet = [2 3 5 8 10]; 20 | for i = 1:length(nSet) 21 | n = nSet(i); 22 | idx = Ind{n}; 23 | for j = 1:size(idx,1) 24 | X = []; 25 | for p = 1:n 26 | X = [X Y(:,:,idx(j,p))]; 27 | end 28 | [D,N] = size(X); 29 | 30 | tic 31 | disp(['For number of clusters n = ', num2str(n),': There are totally ', num2str(size(idx,1)), ' cases. ']); 32 | %% 1. SSC 33 | r = 0; affine = false; outlier = true; rho = 1; 34 | %[missrate1,C] = SSC(X,r,affine,alpha,outlier,rho,s{n}); 35 | missrate1 =0; 36 | missrateTot1{n}(j) = missrate1; 37 | 38 | disp(['------------------------- - - n = ', num2str(n),', j = ', num2str(j), ' of ', num2str(size(idx,1))]); 39 | disp(['* * * SSC missrate 1: ', num2str( missrate1)]); 40 | 41 | %% 2. StrSSC 42 | % paramters for standard SSC 43 | opt.affine =0; 44 | opt.outliers =1; 45 | opt.lambda =alpha; 46 | opt.r =0; % the dimension of the target space when applying PCA or random projection 47 | opt.SSCrho=1; 48 | 49 | % paramters for StrSSC 50 | opt.iter_max =10; % iter_max is for loop in StrLRSCE 51 | opt.nu =1; 52 | opt.gamma0 =gamma0;% This is for reweighting the off-diagonal entries in Z 53 | 54 | 55 | %% paramters for ADMM 56 | %opt.tol =1e-5; 57 | %opt.rho=1.1; 58 | opt.maxIter =150; 59 | %opt.mu_max = 1e8; 60 | %opt.epsilon =1e-3; 61 | %opt.tol =1e-3; 62 | %opt.rho =1.1; 63 | 64 | [missrate2] = StrSSC(X, s{n}', opt); 65 | missrateTot2{n}(j) = 1 - missrate2; 66 | disp(['* * * StrSSC missrate 2: ', num2str(1-missrate2)]); 67 | disp(['------------------------']); 68 | 69 | t2 =toc; 70 | disp(['Esclapsed time: ', num2str( t2 * j )]); 71 | disp(['Reminding time: ', num2str( t2 * (size(idx,1) - j )),'(s) , about ', num2str( t2 * (size(idx,1) - j )/3600), ' hours.']); 72 | 73 | save(results_fn, 'missrateTot1', 'missrateTot2', 'alpha', 'gamma0','opt'); 74 | end 75 | avgmissrate1(n) = mean(missrateTot1{n}); 76 | medmissrate1(n) = median(missrateTot1{n}); 77 | avgmissrate2(n) = mean(missrateTot2{n}); 78 | medmissrate2(n) = median(missrateTot2{n}); 79 | 80 | save(results_fn, 'missrateTot1', 'avgmissrate1', 'medmissrate1', 'missrateTot2', 'avgmissrate2', 'medmissrate2', 'nSet', 'alpha', 'gamma0','opt'); 81 | end -------------------------------------------------------------------------------- /Algorithm/S3C_code/thrC.m: -------------------------------------------------------------------------------- 1 | %-------------------------------------------------------------------------- 2 | % Copyright @ Ehsan Elhamifar, 2012 3 | %-------------------------------------------------------------------------- 4 | 5 | function Cp = thrC(C,ro) 6 | 7 | if (nargin < 2) 8 | ro = 1; 9 | end 10 | 11 | if (ro < 1) 12 | N = size(C,2); 13 | Cp = zeros(N,N); 14 | [S,Ind] = sort(abs(C),1,'descend'); 15 | for i = 1:N 16 | cL1 = sum(S(:,i)); 17 | stop = false; 18 | cSum = 0; t = 0; 19 | while (~stop) 20 | t = t + 1; 21 | cSum = cSum + S(t,i); 22 | if ( cSum >= ro*cL1 ) 23 | stop = true; 24 | Cp(Ind(1:t,i),i) = C(Ind(1:t,i),i); 25 | end 26 | end 27 | end 28 | else 29 | Cp = C; 30 | end -------------------------------------------------------------------------------- /Algorithm/SRLSR_code/SRLSR.m: -------------------------------------------------------------------------------- 1 | function C = SRLSR( X , Par ) 2 | 3 | % Input: 4 | % X ... (L x N) data matrix, where L is the number of features, and 5 | % N is the number of samples. 6 | % Par ... regularization parameters 7 | 8 | % Objective function: 9 | % min_{A} ||X - X * A||_F^2 + lambda * ||A||_F^2 s.t. A>=0, 1'*A=s*1' 10 | 11 | % Output: 12 | % A ... (N x N) is a coefficient matrix 13 | 14 | [D, N] = size (X); 15 | 16 | %% initialization 17 | 18 | % A = eye (N); 19 | % A = rand (N); A(A<0) = 0; 20 | A = zeros (N, N); 21 | C = A; 22 | Delta = zeros (N, N); %C - A; 23 | 24 | %% 25 | tol = 1e-3; 26 | iter = 1; 27 | err1(1) = inf; err2(1) = inf; err3(1) = inf; 28 | terminate = false; 29 | if N < D 30 | XTXinv = (X' * X + Par.rho/2 * eye(N))\eye(N); 31 | else 32 | P = (2/Par.rho * eye(N) - (2/Par.rho)^2 * X' / (2/Par.rho * (X * X') + eye(D)) * X ); 33 | end 34 | while ( ~terminate ) 35 | Apre = A; 36 | Cpre = C; 37 | %% update A the coefficient matrix 38 | if N < D 39 | A = XTXinv * (X' * X + Par.rho/2 * C + 0.5 * Delta); 40 | else 41 | A = P * (X' * X + Par.rho/2 * C + 0.5 * Delta); 42 | end 43 | 44 | %% update C the data term matrix 45 | % Q = (Par.rho*A - Delta)/(Par.s*(2*Par.lambda+Par.rho)); 46 | % C = Par.s*solver_BCLS_closedForm(Q); 47 | 48 | % Q = (Par.rho*A - Delta)/(Par.s*(2*Par.lambda+Par.rho)); 49 | % for i=1:size(Q, 2) 50 | % C(:,i) = projsplx(Q(:,i)); 51 | % end 52 | % C = Par.s*C; 53 | 54 | Q = (Par.rho*A - Delta)/(Par.s*(2*Par.lambda+Par.rho)); 55 | C = SimplexProj(Q'); 56 | C = Par.s*C'; 57 | 58 | %% update Deltas the lagrange multiplier matrix 59 | Delta = Delta + Par.rho * ( C - A); 60 | 61 | % %% update rho the penalty parameter scalar 62 | % Par.rho = min(1e4, Par.mu * Par.rho); 63 | 64 | %% computing errors 65 | err1(iter+1) = errorCoef(C, A); 66 | err2(iter+1) = errorCoef(A, Apre); 67 | err3(iter+1) = errorCoef(C, Cpre); 68 | %err2(iter+1) = errorLinSys(X, A); 69 | if ( (err1(iter+1) >= err1(iter) && err1(iter+1)<=tol && err2(iter+1)<=tol && err3(iter+1)<=tol) || iter >= Par.maxIter ) 70 | terminate = true; 71 | fprintf('err1: %2.4f, err2: %2.4f, iter: %3.0f \n',err1(end), err2(end), iter); 72 | else 73 | if (mod(iter, Par.maxIter)==0) 74 | fprintf('err1: %2.4f, err2: %2.4f, iter: %3.0f \n',err1(end), err2(end), iter); 75 | end 76 | end 77 | 78 | %% next iteration number 79 | iter = iter + 1; 80 | end 81 | end 82 | -------------------------------------------------------------------------------- /Algorithm/SRLSR_code/SimplexProj.m: -------------------------------------------------------------------------------- 1 | function X = SimplexProj(Y) 2 | [N,D] = size(Y); 3 | X = sort(Y,2,'descend'); 4 | Xtmp = (cumsum(X,2)-1)*diag(sparse(1./(1:D))); 5 | X = max(bsxfun(@minus,Y,Xtmp(sub2ind([N,D],(1:N)',sum(X>Xtmp,2)))),0); -------------------------------------------------------------------------------- /Algorithm/SSC_code/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Virgeo/Graph-based-subspsce-clustering/705aaedc2ae2476c3f6e67e87e92bcc736e0934c/Algorithm/SSC_code/.DS_Store -------------------------------------------------------------------------------- /Algorithm/SSC_code/BuildAdjacency.m: -------------------------------------------------------------------------------- 1 | %-------------------------------------------------------------------------- 2 | % This function takes a NxN coefficient matrix and returns a NxN adjacency 3 | % matrix by choosing the K strongest connections in the similarity graph 4 | % CMat: NxN coefficient matrix 5 | % K: number of strongest edges to keep; if K=0 use all the exiting edges 6 | % CKSym: NxN symmetric adjacency matrix 7 | %-------------------------------------------------------------------------- 8 | % Copyright @ Ehsan Elhamifar, 2012 9 | %-------------------------------------------------------------------------- 10 | 11 | 12 | function [CKSym,CAbs] = BuildAdjacency(CMat,K) 13 | 14 | if (nargin < 2) 15 | K = 0; 16 | end 17 | 18 | N = size(CMat,1); 19 | CAbs = abs(CMat); 20 | 21 | [Srt,Ind] = sort( CAbs,1,'descend' ); 22 | 23 | if (K == 0) 24 | for i = 1:N 25 | CAbs(:,i) = CAbs(:,i) ./ (CAbs(Ind(1,i),i)+eps); 26 | end 27 | else 28 | for i = 1:N 29 | for j = 1:K 30 | CAbs(Ind(j,i),i) = CAbs(Ind(j,i),i) ./ (CAbs(Ind(1,i),i)+eps); 31 | end 32 | end 33 | end 34 | 35 | CKSym = CAbs + CAbs'; -------------------------------------------------------------------------------- /Algorithm/SSC_code/DataProjection.m: -------------------------------------------------------------------------------- 1 | %-------------------------------------------------------------------------- 2 | % This function takes the D x N data matrix with columns indicating 3 | % different data points and project the D dimensional data into a r 4 | % dimensional subspace using PCA. 5 | % X: D x N matrix of N data points 6 | % r: dimension of the PCA projection, if r = 0, then no projection 7 | % Xp: r x N matrix of N projectred data points 8 | %-------------------------------------------------------------------------- 9 | % Copyright @ Ehsan Elhamifar, 2012 10 | %-------------------------------------------------------------------------- 11 | 12 | 13 | function Xp = DataProjection(X,r) 14 | 15 | if (nargin < 2) 16 | r = 0; 17 | end 18 | 19 | if (r == 0) 20 | Xp = X; 21 | else 22 | [U,~,~] = svd(X,0); 23 | Xp = U(:,1:r)' * X; 24 | end 25 | -------------------------------------------------------------------------------- /Algorithm/SSC_code/Misclassification.m: -------------------------------------------------------------------------------- 1 | %-------------------------------------------------------------------------- 2 | % This function takes the groups resulted from spectral clutsering and the 3 | % ground truth to compute the misclassification rate. 4 | % groups: [grp1,grp2,grp3] for three different forms of Spectral Clustering 5 | % s: ground truth vector 6 | % Missrate: 3x1 vector with misclassification rates of three forms of 7 | % spectral clustering 8 | %-------------------------------------------------------------------------- 9 | % Copyright @ Ehsan Elhamifar, 2012 10 | %-------------------------------------------------------------------------- 11 | 12 | 13 | function Missrate = Misclassification(groups,s) 14 | 15 | n = max(s); 16 | for i = 1:size(groups,2) 17 | Missrate(i,1) = missclassGroups( groups(:,i),s,n ) ./ length(s); 18 | end -------------------------------------------------------------------------------- /Algorithm/SSC_code/SSC.m: -------------------------------------------------------------------------------- 1 | %-------------------------------------------------------------------------- 2 | % This is the function to call the sparse optimization program, to call the 3 | % spectral clustering algorithm and to compute the clustering error. 4 | % r = projection dimension, if r = 0, then no projection 5 | % affine = use the affine constraint if true 6 | % s = clustering ground-truth 7 | % missrate = clustering error 8 | % CMat = coefficient matrix obtained by SSC 9 | %-------------------------------------------------------------------------- 10 | % Copyright @ Ehsan Elhamifar, 2012 11 | %-------------------------------------------------------------------------- 12 | 13 | function [missrate,CMat] = SSC(X,r,affine,alpha,outlier,rho,s) 14 | 15 | if (nargin < 6) 16 | rho = 1; 17 | end 18 | if (nargin < 5) 19 | outlier = false; 20 | end 21 | if (nargin < 4) 22 | alpha = 20; 23 | end 24 | if (nargin < 3) 25 | affine = false; 26 | end 27 | if (nargin < 2) 28 | r = 0; 29 | end 30 | 31 | n = max(s); 32 | Xp = DataProjection(X,r); 33 | 34 | if (~outlier) 35 | CMat = admmLasso_mat_func(Xp,affine,alpha); 36 | C = CMat; 37 | else 38 | CMat = admmOutlier_mat_func(Xp,affine,alpha); 39 | N = size(Xp,2); 40 | C = CMat(1:N,:); 41 | end 42 | 43 | CKSym = BuildAdjacency(thrC(C,rho)); 44 | grps = SpectralClustering(CKSym,n); 45 | missrate = Misclassification(grps,s); -------------------------------------------------------------------------------- /Algorithm/SSC_code/SimplexProj.m: -------------------------------------------------------------------------------- 1 | function X = SimplexProj(Y) 2 | [N,D] = size(Y); 3 | X = sort(Y,2,'descend'); 4 | Xtmp = (cumsum(X,2)-1)*diag(sparse(1./(1:D))); 5 | X = max(bsxfun(@minus,Y,Xtmp(sub2ind([N,D],(1:N)',sum(X>Xtmp,2)))),0); -------------------------------------------------------------------------------- /Algorithm/SSC_code/YaleBCrop025.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Virgeo/Graph-based-subspsce-clustering/705aaedc2ae2476c3f6e67e87e92bcc736e0934c/Algorithm/SSC_code/YaleBCrop025.mat -------------------------------------------------------------------------------- /Algorithm/SSC_code/admmLasso_mat_func.m: -------------------------------------------------------------------------------- 1 | %-------------------------------------------------------------------------- 2 | % This function takes a DxN matrix of N data points in a D-dimensional 3 | % space and returns a NxN coefficient matrix of the sparse representation 4 | % of each data point in terms of the rest of the points 5 | % Y: DxN data matrix 6 | % affine: if true then enforce the affine constraint 7 | % thr1: stopping threshold for the coefficient error ||Z-C|| 8 | % thr2: stopping threshold for the linear system error ||Y-YZ|| 9 | % maxIter: maximum number of iterations of ADMM 10 | % C2: NxN sparse coefficient matrix 11 | %-------------------------------------------------------------------------- 12 | % Copyright @ Ehsan Elhamifar, 2012 13 | %-------------------------------------------------------------------------- 14 | 15 | function C2 = admmLasso_mat_func(Y,affine,alpha,thr,maxIter) 16 | 17 | if (nargin < 2) 18 | % default subspaces are linear 19 | affine = false; 20 | end 21 | if (nargin < 3) 22 | % default regularizarion parameters 23 | alpha = 800; 24 | end 25 | if (nargin < 4) 26 | % default coefficient error threshold to stop ADMM 27 | % default linear system error threshold to stop ADMM 28 | thr = 2*10^-4; 29 | end 30 | if (nargin < 5) 31 | % default maximum number of iterations of ADMM 32 | maxIter = 200; 33 | end 34 | 35 | if (length(alpha) == 1) 36 | alpha1 = alpha(1); 37 | alpha2 = alpha(1); 38 | elseif (length(alpha) == 2) 39 | alpha1 = alpha(1); 40 | alpha2 = alpha(2); 41 | end 42 | 43 | if (length(thr) == 1) 44 | thr1 = thr(1); 45 | thr2 = thr(1); 46 | elseif (length(thr) == 2) 47 | thr1 = thr(1); 48 | thr2 = thr(2); 49 | end 50 | 51 | N = size(Y,2); 52 | 53 | % setting penalty parameters for the ADMM 54 | mu1 = alpha1 * 1/computeLambda_mat(Y); % ######## 55 | % mu1 = alpha1; %******* self -tune 56 | mu2 = alpha2 * 1; 57 | 58 | if (~affine) 59 | % initialization 60 | A = inv(mu1*(Y'*Y)+mu2*eye(N)); 61 | C1 = zeros(N,N); 62 | Lambda2 = zeros(N,N); 63 | err1 = 10*thr1; err2 = 10*thr2; 64 | i = 1; 65 | % ADMM iterations 66 | while ( err1(i) > thr1 && i < maxIter ) 67 | % updating Z 68 | Z = A * (mu1*(Y'*Y)+mu2*(C1-Lambda2/mu2)); 69 | Z = Z - diag(diag(Z)); 70 | % updating C 71 | C2 = max(0,(abs(Z+Lambda2/mu2) - 1/mu2*ones(N))) .* sign(Z+Lambda2/mu2); 72 | C2 = C2 - diag(diag(C2)); 73 | % updating Lagrange multipliers 74 | Lambda2 = Lambda2 + mu2 * (Z - C2); 75 | % computing errors 76 | err1(i+1) = errorCoef(Z,C2); 77 | err2(i+1) = errorLinSys(Y,Z); 78 | % 79 | C1 = C2; 80 | i = i + 1; 81 | end 82 | fprintf('err1: %2.4f, err2: %2.4f, iter: %3.0f \n',err1(end),err2(end),i); 83 | else 84 | % initialization 85 | A = inv(mu1*(Y'*Y)+mu2*eye(N)+mu2*ones(N,N)); 86 | C1 = zeros(N,N); 87 | Lambda2 = zeros(N,N); 88 | lambda3 = zeros(1,N); 89 | err1 = 10*thr1; err2 = 10*thr2; err3 = 10*thr1; 90 | i = 1; 91 | % ADMM iterations 92 | while ( (err1(i) > thr1 || err3(i) > thr1) && i < maxIter ) 93 | % updating Z 94 | Z = A * (mu1*(Y'*Y)+mu2*(C1-Lambda2/mu2)+mu2*ones(N,1)*(ones(1,N)-lambda3/mu2)); 95 | Z = Z - diag(diag(Z)); 96 | % updating C 97 | C2 = max(0,(abs(Z+Lambda2/mu2) - 1/mu2*ones(N))) .* sign(Z+Lambda2/mu2); 98 | C2 = C2 - diag(diag(C2)); 99 | % updating Lagrange multipliers 100 | Lambda2 = Lambda2 + mu2 * (Z - C2); 101 | lambda3 = lambda3 + mu2 * (ones(1,N)*Z - ones(1,N)); 102 | % computing errors 103 | err1(i+1) = errorCoef(Z,C2); 104 | err2(i+1) = errorLinSys(Y,Z); 105 | err3(i+1) = errorCoef(ones(1,N)*Z,ones(1,N)); 106 | % 107 | C1 = C2; 108 | i = i + 1; 109 | end 110 | fprintf('err1: %2.4f, err2: %2.4f, err3: %2.4f, iter: %3.0f \n',err1(end),err2(end),err3(end),i); 111 | end -------------------------------------------------------------------------------- /Algorithm/SSC_code/admmOutlier_mat_func.m: -------------------------------------------------------------------------------- 1 | %-------------------------------------------------------------------------- 2 | % This function takes a DxN matrix of N data points in a D-dimensional 3 | % space and returns a NxN coefficient matrix of the sparse representation 4 | % of each data point in terms of the rest of the points 5 | % Y: DxN data matrix 6 | % affine: true if enforcing the affine constraint, false otherwise 7 | % thr1: stopping threshold for the coefficient error ||Z-C|| 8 | % thr2: stopping threshold for the linear system error ||Y-YZ|| 9 | % maxIter: maximum number of iterations of ADMM 10 | % C2: NxN sparse coefficient matrix 11 | %-------------------------------------------------------------------------- 12 | % Copyright @ Ehsan Elhamifar, 2012 13 | %-------------------------------------------------------------------------- 14 | 15 | function C2 = admmOutlier_mat_func(Y,affine,alpha,thr,maxIter) 16 | 17 | if (nargin < 2) 18 | % default subspaces are linear 19 | affine = false; 20 | end 21 | if (nargin < 3) 22 | % default regularizarion parameters 23 | alpha = 20; 24 | end 25 | if (nargin < 4) 26 | % default coefficient error threshold to stop ALM 27 | % default linear system error threshold to stop ALM 28 | thr = 2*10^-4; 29 | end 30 | if (nargin < 5) 31 | % default maximum number of iterations of ALM 32 | maxIter = 150; 33 | end 34 | 35 | if (length(alpha) == 1) 36 | alpha1 = alpha(1); 37 | alpha2 = alpha(1); 38 | alpha3 = alpha(1); 39 | elseif (length(alpha) == 2) 40 | alpha1 = alpha(1); 41 | alpha2 = alpha(2); 42 | alpha3 = alpha(2); 43 | elseif (length(alpha) == 3) 44 | alpha1 = alpha(1); 45 | alpha2 = alpha(2); 46 | alpha3 = alpha(3); 47 | end 48 | 49 | if (length(thr) == 1) 50 | thr1 = thr(1); 51 | thr2 = thr(1); 52 | elseif (length(thr) == 2) 53 | thr1 = thr(1); 54 | thr2 = thr(2); 55 | end 56 | 57 | [D,N] = size(Y); 58 | 59 | gamma = alpha3 / norm(Y,1); 60 | P = [Y eye(D)/gamma]; 61 | 62 | % setting penalty parameters for the ADMM 63 | mu1 = alpha1 * 1/computeLambda_mat(Y,P); 64 | mu2 = alpha2 * 1; 65 | 66 | if (~affine) 67 | % initialization 68 | A = inv(mu1*(P'*P)+mu2*eye(N+D)); 69 | C1 = zeros(N+D,N); 70 | Lambda1 = zeros(D,N); 71 | Lambda2 = zeros(N+D,N); 72 | err1 = 10*thr1; err2 = 10*thr2; 73 | i = 1; 74 | % ADMM iterations 75 | while ( (err1(i) > thr1 || err2(i) > thr2) && i < maxIter ) 76 | % updating Z 77 | Z = A * (mu1*P'*(Y+Lambda1/mu1)+mu2*(C1-Lambda2/mu2)); 78 | Z(1:N,:) = Z(1:N,:) - diag(diag(Z(1:N,:))); 79 | % updating C 80 | C2 = max(0,(abs(Z+Lambda2/mu2) - 1/mu2*ones(N+D,N))) .* sign(Z+Lambda2/mu2); 81 | C2(1:N,:) = C2(1:N,:) - diag(diag(C2(1:N,:))); 82 | % updating Lagrange multipliers 83 | Lambda1 = Lambda1 + mu1 * (Y - P * Z); 84 | Lambda2 = Lambda2 + mu2 * (Z - C2); 85 | % computing errors 86 | err1(i+1) = errorCoef(Z,C2); 87 | err2(i+1) = errorLinSys(P,Z); 88 | % 89 | C1 = C2; 90 | i = i + 1; 91 | end 92 | fprintf('err1: %2.4f, err2: %2.4f, iter: %3.0f \n',err1(end),err2(end),i); 93 | else 94 | % initialization 95 | delta = [ones(N,1);zeros(D,1)]; 96 | A = inv(mu1*(P'*P)+mu2*eye(N+D)+mu2*(delta*delta')); 97 | C1 = zeros(N+D,N); 98 | Lambda1 = zeros(D,N); 99 | Lambda2 = zeros(N+D,N); 100 | lambda3 = zeros(1,N); 101 | err1 = 10*thr1; err2 = 10*thr2; err3 = 10*thr1; 102 | i = 1; 103 | % ADMM iterations 104 | while ( (err1(i) > thr1 || err2(i) > thr2 || err3(i) > thr1) && i < maxIter ) 105 | % updating Z 106 | Z = A * (mu1*P'*(Y+Lambda1/mu1)+mu2*(C1-Lambda2/mu2)+mu2*delta*(ones(1,N)-lambda3/mu2)); 107 | Z(1:N,:) = Z(1:N,:) - diag(diag(Z(1:N,:))); 108 | % updating C 109 | C2 = max(0,(abs(Z+Lambda2/mu2) - 1/mu2*ones(N+D,N))) .* sign(Z+Lambda2/mu2); 110 | C2(1:N,:) = C2(1:N,:) - diag(diag(C2(1:N,:))); 111 | % updating Lagrange multipliers 112 | Lambda1 = Lambda1 + mu1 * (Y - P * Z); 113 | Lambda2 = Lambda2 + mu2 * (Z - C2); 114 | lambda3 = lambda3 + mu2 * (delta'*Z - ones(1,N)); 115 | % computing errors 116 | err1(i+1) = errorCoef(Z,C2); 117 | err2(i+1) = errorLinSys(P,Z); 118 | err3(i+1) = errorCoef(delta'*Z,ones(1,N)); 119 | % 120 | C1 = C2; 121 | i = i + 1; 122 | end 123 | fprintf('err1: %2.4f, err2: %2.4f, err3: %2.4f, iter: %3.0f \n',err1(end),err2(end),err3(end),i); 124 | end -------------------------------------------------------------------------------- /Algorithm/SSC_code/computeLambda_mat.m: -------------------------------------------------------------------------------- 1 | %-------------------------------------------------------------------------- 2 | % This function takes a DxN matrix of N data points in a D-dimensional 3 | % space and returns the regularization constant of the L1 norm 4 | % Y: DxN data matrix 5 | % lambda: regularization parameter for lambda*||C||_1 + 0.5 ||Y-YC||_F^2 6 | %-------------------------------------------------------------------------- 7 | % Copyright @ Ehsan Elhamifar, 2012 8 | %-------------------------------------------------------------------------- 9 | 10 | function lambda = computeLambda_mat(Y,P) 11 | 12 | if (nargin < 2) 13 | P = Y; 14 | end 15 | 16 | N = size(Y,2); 17 | T = P' * Y; 18 | T(1:N,:) = T(1:N,:) - diag(diag(T(1:N,:))); 19 | T = abs(T); 20 | lambda = min(max(T,[],1)); 21 | -------------------------------------------------------------------------------- /Algorithm/SSC_code/errorCoef.m: -------------------------------------------------------------------------------- 1 | %-------------------------------------------------------------------------- 2 | % This function computes the maximum error between elements of two 3 | % coefficient matrices 4 | % C: NxN coefficient matrix 5 | % Z: NxN coefficient matrix 6 | % err: infinite norm error between vectorized C and Z 7 | %-------------------------------------------------------------------------- 8 | % Copyright @ Ehsan Elhamifar, 2012 9 | %-------------------------------------------------------------------------- 10 | 11 | function err = errorCoef(Z,C) 12 | 13 | err = max(max( abs(Z-C) )); 14 | %err = norm(Z-C,'fro'); -------------------------------------------------------------------------------- /Algorithm/SSC_code/errorLinSys.m: -------------------------------------------------------------------------------- 1 | %-------------------------------------------------------------------------- 2 | % This function computes the maximum L2-norm error among the columns of the 3 | % residual of a linear system 4 | % Y: DxN data matrix of N data point in a D-dimensional space 5 | % Z: NxN sparse coefficient matrix 6 | % err: maximum L2-norm of the columns of Y-YZ 7 | %-------------------------------------------------------------------------- 8 | % Copyright @ Ehsan Elhamifar, 2012 9 | %-------------------------------------------------------------------------- 10 | 11 | function err = errorLinSys(P,Z) 12 | 13 | [R,N] = size(Z); 14 | if (R > N) 15 | E = P(:,N+1:end) * Z(N+1:end,:); 16 | Y = P(:,1:N); 17 | Y0 = Y - E; 18 | C = Z(1:N,:); 19 | else 20 | Y = P; 21 | Y0 = P; 22 | C = Z; 23 | end 24 | 25 | [Yn,n] = matrixNormalize(Y0); 26 | M = repmat(n,size(Y,1),1); 27 | S = Yn - Y * C ./ M; 28 | err = sqrt( max( sum( S.^2,1 ) ) ); -------------------------------------------------------------------------------- /Algorithm/SSC_code/missclassGroups.m: -------------------------------------------------------------------------------- 1 | %-------------------------------------------------------------------------- 2 | % [miss,index] = missclass(Segmentation,RefSegmentation,ngroups) 3 | % Computes the number of missclassified points in the vector Segmentation. 4 | % Segmentation: 1 by sum(npoints) or sum(ngroups) by 1 vector containing 5 | % the label for each group, ranging from 1 to n 6 | % npoints: 1 by ngroups or ngroups by 1 vector containing the number of 7 | % points in each group. 8 | % ngroups: number of groups 9 | %-------------------------------------------------------------------------- 10 | % Copyright @ Ehsan Elhamifar, 2012 11 | %-------------------------------------------------------------------------- 12 | 13 | 14 | function [miss,index] = missclassGroups(Segmentation,RefSegmentation,ngroups) 15 | 16 | Permutations = perms(1:ngroups); 17 | if(size(Segmentation,2)==1) 18 | Segmentation=Segmentation'; 19 | end 20 | miss = zeros(size(Permutations,1),size(Segmentation,1)); 21 | for k=1:size(Segmentation,1) 22 | for j=1:size(Permutations,1) 23 | miss(j,k) = sum(Segmentation(k,:)~=Permutations(j,RefSegmentation)); 24 | end 25 | end 26 | 27 | [miss,temp] = min(miss,[],1); 28 | index = Permutations(temp,:); 29 | -------------------------------------------------------------------------------- /Algorithm/SSC_code/readme.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Virgeo/Graph-based-subspsce-clustering/705aaedc2ae2476c3f6e67e87e92bcc736e0934c/Algorithm/SSC_code/readme.pdf -------------------------------------------------------------------------------- /Algorithm/SSC_code/readme.rtf: -------------------------------------------------------------------------------- 1 | {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 2 | {\fonttbl\f0\fswiss\fcharset0 Helvetica;} 3 | {\colortbl;\red255\green255\blue255;} 4 | \margl1440\margr1440\vieww17620\viewh12960\viewkind0 5 | \deftab720 6 | \pard\pardeftab720 7 | 8 | \f0\fs26 \cf0 ---------------------------------------------------------------------------------------------------------------------\ 9 | Copyright @ Ehsan Elhamifar, 2012\ 10 | \ 11 | ---------------------------------------------------------------------------------------------------------------------\ 12 | To run the Sparse Subspace Clustering (SSC) algorithm\ 13 | \ 14 | for motion segmentation on the Hopkins 155 dataset, see the following m-file: run_SSC_MS.m. \ 15 | for face clustering on the Extended Yale B dataset, see the following m-file: run_SSC_Faces.m. \ 16 | \ 17 | ---------------------------------------------------------------------------------------------------------------------\ 18 | Terms of use: \ 19 | The code is provided for research purposes only and without any warranty. Any commercial use is prohibited. \ 20 | \ 21 | When using the code in your research work, you should cite the following paper:\ 22 | \ 23 | Sparse Subspace Clustering: Algorithm, Theory, and Applications\ 24 | E. Elhamifar and R. Vidal, \ 25 | Submitted to IEEE Trans. on PAMI, 2011.\ 26 | Available: {\field{\*\fldinst{HYPERLINK "http://arxiv.org/abs/1203.1005"}}{\fldrslt http://arxiv.org/abs/1203.1005}}\ 27 | \ 28 | ---------------------------------------------------------------------------------------------------------------------\ 29 | Please contact Ehsan Elhamifar (ehsan [At] cis [Dot] jhu [Dot] edu) for questions about the code.} -------------------------------------------------------------------------------- /Algorithm/SSC_code/run_SSC_Faces.m: -------------------------------------------------------------------------------- 1 | %-------------------------------------------------------------------------- 2 | % This is the main function to run the SSC algorithm for the face 3 | % clustering problem on the Extended Yale B dataset. 4 | % avgmissrate: the n-th element contains the average clustering error for 5 | % n subjects 6 | % medmissrate: the n-th element contains the median clustering error for 7 | % n subjects 8 | % nSet: the set of the different number of subjects to run the algorithm on 9 | %-------------------------------------------------------------------------- 10 | % Copyright @ Ehsan Elhamifar, 2012 11 | %-------------------------------------------------------------------------- 12 | 13 | clear all, close all 14 | 15 | load YaleBCrop025.mat 16 | 17 | alpha = 20; 18 | 19 | nSet = [2 3 5 8 10]; 20 | for i = 1:length(nSet) 21 | n = nSet(i); 22 | idx = Ind{n}; 23 | for j = 1:size(idx,1) 24 | X = []; 25 | for p = 1:n 26 | X = [X Y(:,:,idx(j,p))]; 27 | end 28 | [D,N] = size(X); 29 | 30 | r = 0; affine = false; outlier = true; rho = 1; 31 | [missrate,C] = SSC(X,r,affine,alpha,outlier,rho,s{n}); 32 | missrateTot{n}(j) = missrate; 33 | 34 | save SSC_Faces.mat missrateTot alpha 35 | end 36 | avgmissrate(n) = mean(missrateTot{n}); 37 | medmissrate(n) = median(missrateTot{n}); 38 | 39 | save SSC_Faces.mat missrateTot avgmissrate medmissrate alpha 40 | end 41 | 42 | save SSC_Faces.mat missrateTot avgmissrate medmissrate alpha -------------------------------------------------------------------------------- /Algorithm/SSC_code/run_SSC_MS.m: -------------------------------------------------------------------------------- 1 | %-------------------------------------------------------------------------- 2 | % This is the main function to run the SSC algorithm for the motion 3 | % segmentation problem on the Hopkins 155 dataset. 4 | % 5 | % cd to the main folder containing the Hopkins 155 sequences 6 | % add the path to the folder "SSC_motion_face" containing these m-files 7 | % 8 | % avgmissrate1: the n-th element contains the average clustering error for 9 | % sequences with n motions (using 2F-dimensional data) 10 | % avgmissrate2: the n-th element contains the average clustering error for 11 | % sequences with n motions (using 4n-dimensional data) 12 | % medmissrate1: the n-th element contains the median clustering error for 13 | % sequences with n motions (using 2F-dimensional data) 14 | % medmissrate2: the n-th element contains the median clustering error for 15 | % sequences with n motions (using 4n-dimensional data) 16 | %-------------------------------------------------------------------------- 17 | % Copyright @ Ehsan Elhamifar, 2012 18 | %-------------------------------------------------------------------------- 19 | 20 | clc, clear all, close all 21 | 22 | cd '/Users/CWG/Documents/m.text/Hopkins155/'; 23 | addpath '/Users/CWG/Documents/m.text/SSC_motion_face/'; 24 | 25 | alpha = 800; 26 | 27 | maxNumGroup = 5; 28 | for i = 1:maxNumGroup 29 | num(i) = 0; 30 | end 31 | 32 | d = dir; 33 | for i = 1:length(d) 34 | if ( (d(i).isdir == 1) && ~strcmp(d(i).name,'.') && ~strcmp(d(i).name,'..') ) 35 | filepath = d(i).name; 36 | eval(['cd ' filepath]); 37 | 38 | f = dir; 39 | foundValidData = false; 40 | for j = 1:length(f) 41 | if ( ~isempty(strfind(f(j).name,'_truth.mat')) ) 42 | ind = j; 43 | foundValidData = true; 44 | break 45 | end 46 | end 47 | eval(['load ' f(ind).name]); 48 | cd .. 49 | 50 | if (foundValidData) 51 | n = max(s); 52 | N = size(x,2); 53 | F = size(x,3); 54 | D = 2*F; 55 | X = reshape(permute(x(1:2,:,:),[1 3 2]),D,N); 56 | 57 | r = 0; affine = true; outlier = false; rho = 0.7; 58 | [missrate1,C1] = SSC(X,r,affine,alpha,outlier,rho,s); 59 | 60 | r = 4*n; affine = true; outlier = false; rho = 0.7; 61 | [missrate2,C2] = SSC(X,r,affine,alpha,outlier,rho,s); 62 | 63 | num(n) = num(n) + 1; 64 | missrateTot1{n}(num(n)) = missrate1; 65 | missrateTot2{n}(num(n)) = missrate2; 66 | 67 | eval(['cd ' filepath]); 68 | % save SSC_MS.mat missrate1 missrate2 C1 C2 alpha 69 | cd .. 70 | end 71 | end 72 | end 73 | 74 | L = [2 3]; 75 | for i = 1:length(L) 76 | j = L(i); 77 | avgmissrate1(j) = mean(missrateTot1{j}); 78 | medmissrate1(j) = median(missrateTot1{j}); 79 | avgmissrate2(j) = mean(missrateTot2{j}); 80 | medmissrate2(j) = median(missrateTot2{j}); 81 | end 82 | % save SSC_MS.mat missrateTot1 avgmissrate1 medmissrate1 missrateTot2 avgmissrate2 medmissrate2 alpha -------------------------------------------------------------------------------- /Algorithm/SSC_code/thrC.m: -------------------------------------------------------------------------------- 1 | %-------------------------------------------------------------------------- 2 | % Copyright @ Ehsan Elhamifar, 2012 3 | %-------------------------------------------------------------------------- 4 | 5 | function Cp = thrC(C,ro) 6 | 7 | if (nargin < 2) 8 | ro = 1; 9 | end 10 | 11 | if (ro < 1) 12 | N = size(C,2); 13 | Cp = zeros(N,N); 14 | [S,Ind] = sort(abs(C),1,'descend'); 15 | for i = 1:N 16 | cL1 = sum(S(:,i)); 17 | stop = false; 18 | cSum = 0; t = 0; 19 | while (~stop) 20 | t = t + 1; 21 | cSum = cSum + S(t,i); 22 | if ( cSum >= ro*cL1 ) 23 | stop = true; 24 | Cp(Ind(1:t,i),i) = C(Ind(1:t,i),i); 25 | end 26 | end 27 | end 28 | else 29 | Cp = C; 30 | end -------------------------------------------------------------------------------- /Database/AR_55_40.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Virgeo/Graph-based-subspsce-clustering/705aaedc2ae2476c3f6e67e87e92bcc736e0934c/Database/AR_55_40.mat -------------------------------------------------------------------------------- /Database/AR_glass.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Virgeo/Graph-based-subspsce-clustering/705aaedc2ae2476c3f6e67e87e92bcc736e0934c/Database/AR_glass.mat -------------------------------------------------------------------------------- /Database/AR_scarve.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Virgeo/Graph-based-subspsce-clustering/705aaedc2ae2476c3f6e67e87e92bcc736e0934c/Database/AR_scarve.mat -------------------------------------------------------------------------------- /Database/CMU_PIE.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Virgeo/Graph-based-subspsce-clustering/705aaedc2ae2476c3f6e67e87e92bcc736e0934c/Database/CMU_PIE.mat -------------------------------------------------------------------------------- /Database/COIL100.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Virgeo/Graph-based-subspsce-clustering/705aaedc2ae2476c3f6e67e87e92bcc736e0934c/Database/COIL100.mat -------------------------------------------------------------------------------- /Database/COIL100_10.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Virgeo/Graph-based-subspsce-clustering/705aaedc2ae2476c3f6e67e87e92bcc736e0934c/Database/COIL100_10.mat -------------------------------------------------------------------------------- /Database/COIL_20.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Virgeo/Graph-based-subspsce-clustering/705aaedc2ae2476c3f6e67e87e92bcc736e0934c/Database/COIL_20.mat -------------------------------------------------------------------------------- /Database/Jaffe.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Virgeo/Graph-based-subspsce-clustering/705aaedc2ae2476c3f6e67e87e92bcc736e0934c/Database/Jaffe.mat -------------------------------------------------------------------------------- /Database/MNIST_train.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Virgeo/Graph-based-subspsce-clustering/705aaedc2ae2476c3f6e67e87e92bcc736e0934c/Database/MNIST_train.mat -------------------------------------------------------------------------------- /Database/ORL.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Virgeo/Graph-based-subspsce-clustering/705aaedc2ae2476c3f6e67e87e92bcc736e0934c/Database/ORL.mat -------------------------------------------------------------------------------- /Database/UMIST.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Virgeo/Graph-based-subspsce-clustering/705aaedc2ae2476c3f6e67e87e92bcc736e0934c/Database/UMIST.mat -------------------------------------------------------------------------------- /Database/Yale.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Virgeo/Graph-based-subspsce-clustering/705aaedc2ae2476c3f6e67e87e92bcc736e0934c/Database/Yale.mat -------------------------------------------------------------------------------- /Database/YaleB.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Virgeo/Graph-based-subspsce-clustering/705aaedc2ae2476c3f6e67e87e92bcc736e0934c/Database/YaleB.mat -------------------------------------------------------------------------------- /Database/usps_train.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Virgeo/Graph-based-subspsce-clustering/705aaedc2ae2476c3f6e67e87e92bcc736e0934c/Database/usps_train.mat -------------------------------------------------------------------------------- /Database/usps_train_1k.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Virgeo/Graph-based-subspsce-clustering/705aaedc2ae2476c3f6e67e87e92bcc736e0934c/Database/usps_train_1k.mat -------------------------------------------------------------------------------- /Measure/ACC/acc.m: -------------------------------------------------------------------------------- 1 | function [ac] = acc(label_pre,label_gt) 2 | %Measure percentage of Accuracy and the Rand index of clustering results 3 | % The number of class must equal to the number cluster 4 | 5 | %Output 6 | % Acc = Accuracy of clustering results 7 | % rand_index = Rand's Index, measure an agreement of the clustering results 8 | % match = 2xk mxtrix which are the best match of the Target and clustering results 9 | 10 | %Input 11 | % T = 1xn target index 12 | % idx =1xn matrix of the clustering results 13 | 14 | % EX: 15 | % X=[randn(200,2);randn(200,2)+6,;[randn(200,1)+12,randn(200,1)]]; T=[ones(200,1);ones(200,1).*2;ones(200,1).*3]; 16 | % idx=kmeans(X,3,'emptyaction','singleton','Replicates',5); 17 | % [Acc,rand_index,match]=Acc_measure(T,idx) 18 | 19 | res = bestMap(label_gt(:), label_pre(:)); 20 | ac = length(find(label_gt(:) == res(:)))/length(label_gt(:)); 21 | 22 | return; 23 | 24 | k=max(T); 25 | n=length(T); 26 | for i=1:k 27 | temp=find(T==i); 28 | a{i}=temp; %#ok 29 | end 30 | 31 | b1=[]; 32 | t1=zeros(1,k); 33 | for i=1:k 34 | tt1=find(idx==i); 35 | for j=1:k 36 | t1(j)=sum(ismember(tt1,a{j})); 37 | end 38 | b1=[b1;t1]; %#ok 39 | end 40 | Members=zeros(1,k); 41 | 42 | P = perms((1:k)); 43 | Acc1=0; 44 | for pi=1:size(P,1) 45 | for ki=1:k 46 | Members(ki)=b1(P(pi,ki),ki); 47 | end 48 | if sum(Members)>Acc1 49 | match=P(pi,:); 50 | Acc1=sum(Members); 51 | end 52 | end 53 | 54 | rand_ss1=0; 55 | rand_dd1=0; 56 | for xi=1:n-1 57 | for xj=xi+1:n 58 | rand_ss1=rand_ss1+((idx(xi)==idx(xj))&&(T(xi)==T(xj))); 59 | rand_dd1=rand_dd1+((idx(xi)~=idx(xj))&&(T(xi)~=T(xj))); 60 | end 61 | end 62 | rand_index=200*(rand_ss1+rand_dd1)/(n*(n-1)); 63 | Acc=Acc1/n*100; 64 | match=[1:k;match]; -------------------------------------------------------------------------------- /Measure/ACC/bestMap.m: -------------------------------------------------------------------------------- 1 | function [newL2] = bestMap(L1,L2) 2 | %bestmap: permute labels of L2 to match L1 as good as possible 3 | % [newL2] = bestMap(L1,L2); 4 | % 5 | % version 2.0 --May/2007 6 | % version 1.0 --November/2003 7 | % 8 | % Written by Deng Cai (dengcai AT gmail.com) 9 | 10 | 11 | %=========== 12 | 13 | L1 = L1(:); 14 | L2 = L2(:); 15 | if size(L1) ~= size(L2) 16 | error('size(L1) must == size(L2)'); 17 | end 18 | 19 | Label1 = unique(L1); 20 | nClass1 = length(Label1); 21 | Label2 = unique(L2); 22 | nClass2 = length(Label2); 23 | 24 | nClass = max(nClass1,nClass2); 25 | G = zeros(nClass); 26 | for i=1:nClass1 27 | for j=1:nClass2 28 | G(i,j) = length(find(L1 == Label1(i) & L2 == Label2(j))); 29 | end 30 | end 31 | 32 | [c,t] = hungarian(-G); 33 | newL2 = zeros(size(L2)); 34 | for i=1:nClass2 35 | newL2(L2 == Label2(i)) = Label1(c(i)); 36 | end -------------------------------------------------------------------------------- /Measure/ACC/hungarian.m: -------------------------------------------------------------------------------- 1 | function [C,T]=hungarian(A) 2 | %HUNGARIAN Solve the Assignment problem using the Hungarian method. 3 | % 4 | %[C,T]=hungarian(A) 5 | %A - a square cost matrix. 6 | %C - the optimal assignment. 7 | %T - the cost of the optimal assignment. 8 | %s.t. T = trace(A(C,:)) is minimized over all possible assignments. 9 | 10 | % Adapted from the FORTRAN IV code in Carpaneto and Toth, "Algorithm 548: 11 | % Solution of the assignment problem [H]", ACM Transactions on 12 | % Mathematical Software, 6(1):104-111, 1980. 13 | 14 | % v1.0 96-06-14. Niclas Borlin, niclas@cs.umu.se. 15 | % Department of Computing Science, Ume? University, 16 | % Sweden. 17 | % All standard disclaimers apply. 18 | 19 | % A substantial effort was put into this code. If you use it for a 20 | % publication or otherwise, please include an acknowledgement or at least 21 | % notify me by email. /Niclas 22 | 23 | [m,n]=size(A); 24 | 25 | if (m~=n) 26 | error('HUNGARIAN: Cost matrix must be square!'); 27 | end 28 | 29 | % Save original cost matrix. 30 | orig=A; 31 | 32 | % Reduce matrix. 33 | A=hminired(A); 34 | 35 | % Do an initial assignment. 36 | [A,C,U]=hminiass(A); 37 | 38 | % Repeat while we have unassigned rows. 39 | while (U(n+1)) 40 | % Start with no path, no unchecked zeros, and no unexplored rows. 41 | LR=zeros(1,n); 42 | LC=zeros(1,n); 43 | CH=zeros(1,n); 44 | RH=[zeros(1,n) -1]; 45 | 46 | % No labelled columns. 47 | SLC=[]; 48 | 49 | % Start path in first unassigned row. 50 | r=U(n+1); 51 | % Mark row with end-of-path label. 52 | LR(r)=-1; 53 | % Insert row first in labelled row set. 54 | SLR=r; 55 | 56 | % Repeat until we manage to find an assignable zero. 57 | while (1) 58 | % If there are free zeros in row r 59 | if (A(r,n+1)~=0) 60 | % ...get column of first free zero. 61 | l=-A(r,n+1); 62 | 63 | % If there are more free zeros in row r and row r in not 64 | % yet marked as unexplored.. 65 | if (A(r,l)~=0 & RH(r)==0) 66 | % Insert row r first in unexplored list. 67 | RH(r)=RH(n+1); 68 | RH(n+1)=r; 69 | 70 | % Mark in which column the next unexplored zero in this row 71 | % is. 72 | CH(r)=-A(r,l); 73 | end 74 | else 75 | % If all rows are explored.. 76 | if (RH(n+1)<=0) 77 | % Reduce matrix. 78 | [A,CH,RH]=hmreduce(A,CH,RH,LC,LR,SLC,SLR); 79 | end 80 | 81 | % Re-start with first unexplored row. 82 | r=RH(n+1); 83 | % Get column of next free zero in row r. 84 | l=CH(r); 85 | % Advance "column of next free zero". 86 | CH(r)=-A(r,l); 87 | % If this zero is last in the list.. 88 | if (A(r,l)==0) 89 | % ...remove row r from unexplored list. 90 | RH(n+1)=RH(r); 91 | RH(r)=0; 92 | end 93 | end 94 | 95 | % While the column l is labelled, i.e. in path. 96 | while (LC(l)~=0) 97 | % If row r is explored.. 98 | if (RH(r)==0) 99 | % If all rows are explored.. 100 | if (RH(n+1)<=0) 101 | % Reduce cost matrix. 102 | [A,CH,RH]=hmreduce(A,CH,RH,LC,LR,SLC,SLR); 103 | end 104 | 105 | % Re-start with first unexplored row. 106 | r=RH(n+1); 107 | end 108 | 109 | % Get column of next free zero in row r. 110 | l=CH(r); 111 | 112 | % Advance "column of next free zero". 113 | CH(r)=-A(r,l); 114 | 115 | % If this zero is last in list.. 116 | if(A(r,l)==0) 117 | % ...remove row r from unexplored list. 118 | RH(n+1)=RH(r); 119 | RH(r)=0; 120 | end 121 | end 122 | 123 | % If the column found is unassigned.. 124 | if (C(l)==0) 125 | % Flip all zeros along the path in LR,LC. 126 | [A,C,U]=hmflip(A,C,LC,LR,U,l,r); 127 | % ...and exit to continue with next unassigned row. 128 | break; 129 | else 130 | % ...else add zero to path. 131 | 132 | % Label column l with row r. 133 | LC(l)=r; 134 | 135 | % Add l to the set of labelled columns. 136 | SLC=[SLC l]; 137 | 138 | % Continue with the row assigned to column l. 139 | r=C(l); 140 | 141 | % Label row r with column l. 142 | LR(r)=l; 143 | 144 | % Add r to the set of labelled rows. 145 | SLR=[SLR r]; 146 | end 147 | end 148 | end 149 | 150 | % Calculate the total cost. 151 | T=sum(orig(logical(sparse(C,1:size(orig,2),1)))); 152 | 153 | 154 | function A=hminired(A) 155 | %HMINIRED Initial reduction of cost matrix for the Hungarian method. 156 | % 157 | %B=assredin(A) 158 | %A - the unreduced cost matris. 159 | %B - the reduced cost matrix with linked zeros in each row. 160 | 161 | % v1.0 96-06-13. Niclas Borlin, niclas@cs.umu.se. 162 | 163 | [m,n]=size(A); 164 | 165 | % Subtract column-minimum values from each column. 166 | colMin=min(A); 167 | A=A-colMin(ones(n,1),:); 168 | 169 | % Subtract row-minimum values from each row. 170 | rowMin=min(A')'; 171 | A=A-rowMin(:,ones(1,n)); 172 | 173 | % Get positions of all zeros. 174 | [i,j]=find(A==0); 175 | 176 | % Extend A to give room for row zero list header column. 177 | A(1,n+1)=0; 178 | for k=1:n 179 | % Get all column in this row. 180 | cols=j(k==i)'; 181 | % Insert pointers in matrix. 182 | A(k,[n+1 cols])=[-cols 0]; 183 | end 184 | 185 | 186 | function [A,C,U]=hminiass(A) 187 | %HMINIASS Initial assignment of the Hungarian method. 188 | % 189 | %[B,C,U]=hminiass(A) 190 | %A - the reduced cost matrix. 191 | %B - the reduced cost matrix, with assigned zeros removed from lists. 192 | %C - a vector. C(J)=I means row I is assigned to column J, 193 | % i.e. there is an assigned zero in position I,J. 194 | %U - a vector with a linked list of unassigned rows. 195 | 196 | % v1.0 96-06-14. Niclas Borlin, niclas@cs.umu.se. 197 | 198 | [n,np1]=size(A); 199 | 200 | % Initalize return vectors. 201 | C=zeros(1,n); 202 | U=zeros(1,n+1); 203 | 204 | % Initialize last/next zero "pointers". 205 | LZ=zeros(1,n); 206 | NZ=zeros(1,n); 207 | 208 | for i=1:n 209 | % Set j to first unassigned zero in row i. 210 | lj=n+1; 211 | j=-A(i,lj); 212 | 213 | % Repeat until we have no more zeros (j==0) or we find a zero 214 | % in an unassigned column (c(j)==0). 215 | 216 | while (C(j)~=0) 217 | % Advance lj and j in zero list. 218 | lj=j; 219 | j=-A(i,lj); 220 | 221 | % Stop if we hit end of list. 222 | if (j==0) 223 | break; 224 | end 225 | end 226 | 227 | if (j~=0) 228 | % We found a zero in an unassigned column. 229 | 230 | % Assign row i to column j. 231 | C(j)=i; 232 | 233 | % Remove A(i,j) from unassigned zero list. 234 | A(i,lj)=A(i,j); 235 | 236 | % Update next/last unassigned zero pointers. 237 | NZ(i)=-A(i,j); 238 | LZ(i)=lj; 239 | 240 | % Indicate A(i,j) is an assigned zero. 241 | A(i,j)=0; 242 | else 243 | % We found no zero in an unassigned column. 244 | 245 | % Check all zeros in this row. 246 | 247 | lj=n+1; 248 | j=-A(i,lj); 249 | 250 | % Check all zeros in this row for a suitable zero in another row. 251 | while (j~=0) 252 | % Check the in the row assigned to this column. 253 | r=C(j); 254 | 255 | % Pick up last/next pointers. 256 | lm=LZ(r); 257 | m=NZ(r); 258 | 259 | % Check all unchecked zeros in free list of this row. 260 | while (m~=0) 261 | % Stop if we find an unassigned column. 262 | if (C(m)==0) 263 | break; 264 | end 265 | 266 | % Advance one step in list. 267 | lm=m; 268 | m=-A(r,lm); 269 | end 270 | 271 | if (m==0) 272 | % We failed on row r. Continue with next zero on row i. 273 | lj=j; 274 | j=-A(i,lj); 275 | else 276 | % We found a zero in an unassigned column. 277 | 278 | % Replace zero at (r,m) in unassigned list with zero at (r,j) 279 | A(r,lm)=-j; 280 | A(r,j)=A(r,m); 281 | 282 | % Update last/next pointers in row r. 283 | NZ(r)=-A(r,m); 284 | LZ(r)=j; 285 | 286 | % Mark A(r,m) as an assigned zero in the matrix . . . 287 | A(r,m)=0; 288 | 289 | % ...and in the assignment vector. 290 | C(m)=r; 291 | 292 | % Remove A(i,j) from unassigned list. 293 | A(i,lj)=A(i,j); 294 | 295 | % Update last/next pointers in row r. 296 | NZ(i)=-A(i,j); 297 | LZ(i)=lj; 298 | 299 | % Mark A(r,m) as an assigned zero in the matrix . . . 300 | A(i,j)=0; 301 | 302 | % ...and in the assignment vector. 303 | C(j)=i; 304 | 305 | % Stop search. 306 | break; 307 | end 308 | end 309 | end 310 | end 311 | 312 | % Create vector with list of unassigned rows. 313 | 314 | % Mark all rows have assignment. 315 | r=zeros(1,n); 316 | rows=C(C~=0); 317 | r(rows)=rows; 318 | empty=find(r==0); 319 | 320 | % Create vector with linked list of unassigned rows. 321 | U=zeros(1,n+1); 322 | U([n+1 empty])=[empty 0]; 323 | 324 | 325 | function [A,C,U]=hmflip(A,C,LC,LR,U,l,r) 326 | %HMFLIP Flip assignment state of all zeros along a path. 327 | % 328 | %[A,C,U]=hmflip(A,C,LC,LR,U,l,r) 329 | %Input: 330 | %A - the cost matrix. 331 | %C - the assignment vector. 332 | %LC - the column label vector. 333 | %LR - the row label vector. 334 | %U - the 335 | %r,l - position of last zero in path. 336 | %Output: 337 | %A - updated cost matrix. 338 | %C - updated assignment vector. 339 | %U - updated unassigned row list vector. 340 | 341 | % v1.0 96-06-14. Niclas Borlin, niclas@cs.umu.se. 342 | 343 | n=size(A,1); 344 | 345 | while (1) 346 | % Move assignment in column l to row r. 347 | C(l)=r; 348 | 349 | % Find zero to be removed from zero list.. 350 | 351 | % Find zero before this. 352 | m=find(A(r,:)==-l); 353 | 354 | % Link past this zero. 355 | A(r,m)=A(r,l); 356 | 357 | A(r,l)=0; 358 | 359 | % If this was the first zero of the path.. 360 | if (LR(r)<0) 361 | ...remove row from unassigned row list and return. 362 | U(n+1)=U(r); 363 | U(r)=0; 364 | return; 365 | else 366 | 367 | % Move back in this row along the path and get column of next zero. 368 | l=LR(r); 369 | 370 | % Insert zero at (r,l) first in zero list. 371 | A(r,l)=A(r,n+1); 372 | A(r,n+1)=-l; 373 | 374 | % Continue back along the column to get row of next zero in path. 375 | r=LC(l); 376 | end 377 | end 378 | 379 | 380 | function [A,CH,RH]=hmreduce(A,CH,RH,LC,LR,SLC,SLR) 381 | %HMREDUCE Reduce parts of cost matrix in the Hungerian method. 382 | % 383 | %[A,CH,RH]=hmreduce(A,CH,RH,LC,LR,SLC,SLR) 384 | %Input: 385 | %A - Cost matrix. 386 | %CH - vector of column of 'next zeros' in each row. 387 | %RH - vector with list of unexplored rows. 388 | %LC - column labels. 389 | %RC - row labels. 390 | %SLC - set of column labels. 391 | %SLR - set of row labels. 392 | % 393 | %Output: 394 | %A - Reduced cost matrix. 395 | %CH - Updated vector of 'next zeros' in each row. 396 | %RH - Updated vector of unexplored rows. 397 | 398 | % v1.0 96-06-14. Niclas Borlin, niclas@cs.umu.se. 399 | 400 | n=size(A,1); 401 | 402 | % Find which rows are covered, i.e. unlabelled. 403 | coveredRows=LR==0; 404 | 405 | % Find which columns are covered, i.e. labelled. 406 | coveredCols=LC~=0; 407 | 408 | r=find(~coveredRows); 409 | c=find(~coveredCols); 410 | 411 | % Get minimum of uncovered elements. 412 | m=min(min(A(r,c))); 413 | 414 | % Subtract minimum from all uncovered elements. 415 | A(r,c)=A(r,c)-m; 416 | 417 | % Check all uncovered columns.. 418 | for j=c 419 | % ...and uncovered rows in path order.. 420 | for i=SLR 421 | % If this is a (new) zero.. 422 | if (A(i,j)==0) 423 | % If the row is not in unexplored list.. 424 | if (RH(i)==0) 425 | % ...insert it first in unexplored list. 426 | RH(i)=RH(n+1); 427 | RH(n+1)=i; 428 | % Mark this zero as "next free" in this row. 429 | CH(i)=j; 430 | end 431 | % Find last unassigned zero on row I. 432 | row=A(i,:); 433 | colsInList=-row(row<0); 434 | if (length(colsInList)==0) 435 | % No zeros in the list. 436 | l=n+1; 437 | else 438 | l=colsInList(row(colsInList)==0); 439 | end 440 | % Append this zero to end of list. 441 | A(i,l)=-j; 442 | end 443 | end 444 | end 445 | 446 | % Add minimum to all doubly covered elements. 447 | r=find(coveredRows); 448 | c=find(coveredCols); 449 | 450 | % Take care of the zeros we will remove. 451 | [i,j]=find(A(r,c)<=0); 452 | 453 | i=r(i); 454 | j=c(j); 455 | 456 | for k=1:length(i) 457 | % Find zero before this in this row. 458 | lj=find(A(i(k),:)==-j(k)); 459 | % Link past it. 460 | A(i(k),lj)=A(i(k),j(k)); 461 | % Mark it as assigned. 462 | A(i(k),j(k))=0; 463 | end 464 | 465 | A(r,c)=A(r,c)+m; -------------------------------------------------------------------------------- /Measure/NMI/calc_NMI.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Virgeo/Graph-based-subspsce-clustering/705aaedc2ae2476c3f6e67e87e92bcc736e0934c/Measure/NMI/calc_NMI.m -------------------------------------------------------------------------------- /Measure/NMI/nmi.m: -------------------------------------------------------------------------------- 1 | function v = nmi(label, result) 2 | % Nomalized mutual information 3 | % Written by Mo Chen (mochen@ie.cuhk.edu.hk). March 2009. 4 | assert(length(label) == length(result)); 5 | 6 | label = label(:); 7 | result = result(:); 8 | 9 | n = length(label); 10 | 11 | label_unique = unique(label); 12 | result_unique = unique(result); 13 | 14 | % check the integrity of result 15 | % if length(label_unique) ~= length(result_unique) 16 | % error('The clustering result is not consistent with label.'); 17 | % end; 18 | 19 | c = length(label_unique); 20 | 21 | % distribution of result and label 22 | Ml = double(repmat(label,1,c) == repmat(label_unique',n,1)); 23 | Mr = double(repmat(result,1,c) == repmat(result_unique',n,1)); 24 | Pl = sum(Ml)/n; 25 | Pr = sum(Mr)/n; 26 | 27 | % entropy of Pr and Pl 28 | Hl = -sum( Pl .* log2( Pl + eps ) ); 29 | Hr = -sum( Pr .* log2( Pr + eps ) ); 30 | 31 | 32 | % joint entropy of Pr and Pl 33 | % M = zeros(c); 34 | % for I = 1:c 35 | % for J = 1:c 36 | % M(I,J) = sum(result==result_unique(I)&label==label_unique(J)); 37 | % end; 38 | % end; 39 | % M = M / n; 40 | M = Ml'*Mr/n; 41 | Hlr = -sum( M(:) .* log2( M(:) + eps ) ); 42 | 43 | % mutual information 44 | MI = Hl + Hr - Hlr; 45 | 46 | % normalized mutual information 47 | v = sqrt((MI/Hl)*(MI/Hr)) ; -------------------------------------------------------------------------------- /Measure/NMI/nmi_jwy.m: -------------------------------------------------------------------------------- 1 | function v = nmi_jwy(label_gt, label_pre) 2 | % Standard version of Nomalized mutual information which can cope with different number of clusters between label_gt and label_pre 3 | % Written by Jianwei Yang (jw2yang@vt.edu). August 2015. 4 | size = length(label_gt); 5 | 6 | %% entropy_gt 7 | label_gt_unique = unique(label_gt); 8 | hist_label_gt = zeros(1, length(label_gt_unique)); 9 | for i = 1:length(label_gt_unique) 10 | hist_label_gt(i) = sum(label_gt == label_gt_unique(i)); 11 | end 12 | 13 | % calculate entropy for label_gt 14 | ent_gt = 0; 15 | for i = 1:length(label_gt_unique) 16 | ent_gt = ent_gt + hist_label_gt(i) * log(hist_label_gt(i) / size); 17 | end 18 | 19 | %% entropy_pred 20 | idx = label_pre; 21 | label_pred_unique = unique(idx); 22 | hist_label_pred = zeros(1, length(label_pred_unique)); 23 | for i = 1:length(label_pred_unique) 24 | hist_label_pred(i) = sum(idx == label_pred_unique(i)); 25 | end 26 | 27 | % calculate entropy for label_pred 28 | ent_pred = 0; 29 | for i = 1:length(hist_label_pred) 30 | ent_pred = ent_pred + hist_label_pred(i) * log(hist_label_pred(i) / size); 31 | end 32 | 33 | %% mutual information 34 | mutual_info = 0; 35 | for i = 1:length(label_gt_unique) 36 | labels_i = find(label_gt == label_gt_unique(i)); 37 | for j = 1:length(label_pred_unique) 38 | labels_j = find(idx == label_pred_unique(j)); 39 | n_h_l = 0; 40 | for m = 1:length(labels_i) 41 | for n = 1:length(labels_j) 42 | if labels_i(m) == labels_j(n) 43 | n_h_l = n_h_l + 1; 44 | end 45 | end 46 | end 47 | 48 | if n_h_l == 0 49 | continue; 50 | end 51 | mutual_info = mutual_info + ... 52 | n_h_l * log(size * n_h_l / length(labels_i) / length(labels_j)); 53 | end 54 | end 55 | % mutual_info 56 | v = mutual_info / sqrt(ent_gt * ent_pred); -------------------------------------------------------------------------------- /Tools/SpectralClustering.m: -------------------------------------------------------------------------------- 1 | %-------------------------------------------------------------------------- 2 | % This function takes an adjacency matrix of a graph and computes the 3 | % clustering of the nodes using the spectral clustering algorithm of 4 | % Ng, Jordan and Weiss. 5 | % CMat: NxN adjacency matrix 6 | % n: number of groups for clustering 7 | % groups: N-dimensional vector containing the memberships of the N points 8 | % to the n groups obtained by spectral clustering 9 | %-------------------------------------------------------------------------- 10 | % Copyright @ Ehsan Elhamifar, 2012 11 | %-------------------------------------------------------------------------- 12 | 13 | function groups = SpectralClustering(CKSym,n) 14 | 15 | warning off; 16 | N = size(CKSym,1); 17 | MAXiter = 1000; % Maximum number of iterations for KMeans 18 | REPlic = 20; % Number of replications for KMeans 19 | CKSym = (CKSym + CKSym')/2; 20 | 21 | % Normalized spectral clustering according to Ng & Jordan & Weiss 22 | % using Normalized Symmetric Laplacian L = I - D^{-1/2} W D^{-1/2} 23 | 24 | DN = diag( 1./sqrt(sum(CKSym)+eps) ); 25 | LapN = speye(N) - DN * CKSym * DN; 26 | % DN = diag(sum(CKSym)); 27 | % LapN = DN - CKSym; 28 | [uN,sN,vN] = svd(LapN); 29 | kerN = vN(:,N-n+1:N); 30 | for i = 1:N 31 | kerNS(i,:) = kerN(i,:) ./ norm(kerN(i,:)+eps); 32 | end 33 | groups = kmeans(kerNS,n,'maxiter',MAXiter,'replicates',REPlic,'EmptyAction','singleton'); -------------------------------------------------------------------------------- /Tools/matrixNormalize.m: -------------------------------------------------------------------------------- 1 | %-------------------------------------------------------------------------- 2 | % This function normalizes the columns of a given matrix 3 | % Y: DxN data matrix 4 | % Yn: DxN data matrix whose columns have unit Euclidean norm 5 | % n: N-dimensional vector of the norms of the columns of Y 6 | %-------------------------------------------------------------------------- 7 | % Copyright @ Ehsan Elhamifar, 2012 8 | %-------------------------------------------------------------------------- 9 | 10 | function [Y,n] = matrixNormalize(Y) 11 | 12 | for i = 1:size(Y,2) 13 | n(i) = norm(Y(:,i)); 14 | Y(:,i) = Y(:,i) ./ n(i); 15 | end -------------------------------------------------------------------------------- /Tools/project_simplex.m: -------------------------------------------------------------------------------- 1 | function X = project_simplex(B) 2 | 3 | % Project onto the probability simplex 4 | % min_X ||X-B||_F 5 | % s.t Xe=e, X>=0 where e is the constant one vector. 6 | % 7 | % --------------------------------------------- 8 | % Input: 9 | % B - n*d matrix 10 | % 11 | % Output: 12 | % X - n*d matrix 13 | % 14 | 15 | [n,m] = size(B); 16 | A = repmat(1:m,n,1); 17 | B_sort = sort(B,2,'descend'); 18 | cum_B = cumsum(B_sort,2); 19 | sigma = B_sort-(cum_B-1)./A; 20 | tmp = sigma>0; 21 | idx = sum(tmp,2); 22 | tmp = B_sort-sigma; 23 | sigma = diag(tmp(:,idx)); 24 | sigma = repmat(sigma,1,m); 25 | X = max(B-sigma,0); -------------------------------------------------------------------------------- /Tools/prox_l1.m: -------------------------------------------------------------------------------- 1 | function x = prox_l1(b,lambda) 2 | 3 | % The proximal operator of the l1 norm 4 | % 5 | % min_x lambda*||x||_1+0.5*||x-b||_2^2 6 | % 7 | % version 1.0 - 18/06/2016 8 | % 9 | % Written by Canyi Lu (canyilu@gmail.com) 10 | % 11 | 12 | x = max(0,b-lambda)+min(0,b+lambda); -------------------------------------------------------------------------------- /Tools/prox_l21.m: -------------------------------------------------------------------------------- 1 | function X = prox_l21(B,lambda) 2 | 3 | % The proximal operator of the l21 norm of a matrix 4 | % l21 norm is the sum of the l2 norm of all columns of a matrix 5 | % 6 | % min_X lambda*||X||_{2,1}+0.5*||X-B||_2^2 7 | % 8 | % version 1.0 - 18/06/2016 9 | % 10 | % Written by Canyi Lu (canyilu@gmail.com) 11 | % 12 | 13 | X = zeros(size(B)); 14 | for i = 1 : size(X,2) 15 | nxi = norm(B(:,i)); 16 | if nxi > lambda 17 | X(:,i) = (1-lambda/nxi)*B(:,i); 18 | end 19 | end -------------------------------------------------------------------------------- /Tools/prox_nuclear.m: -------------------------------------------------------------------------------- 1 | function [X,nuclearnorm] = prox_nuclear(B,lambda) 2 | 3 | % The proximal operator of the nuclear norm of a matrix 4 | % 5 | % min_X lambda*||X||_*+0.5*||X-B||_F^2 6 | % 7 | % version 1.0 - 18/06/2016 8 | % 9 | % Written by Canyi Lu (canyilu@gmail.com) 10 | % 11 | 12 | [U,S,V] = svd(B,'econ'); 13 | S = diag(S); 14 | svp = length(find(S>lambda)); 15 | if svp>=1 16 | S = S(1:svp)-lambda; 17 | X = U(:,1:svp)*diag(S)*V(:,1:svp)'; 18 | nuclearnorm = sum(S); 19 | else 20 | X = zeros(size(B)); 21 | nuclearnorm = 0; 22 | end -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | --------------------------------------------------------------------------------