├── data_BC.mat ├── data_PD.mat ├── Ncut ├── cimgnbmap.mexw64 ├── sparsifyc.mexw64 ├── spmtimesd.mexw64 ├── affinityic.mexw64 ├── cimgnbmap.mexmaci64 ├── sparsifyc.mexmaci64 ├── spmtimesd.mexmaci64 ├── affinityic.mexmaci64 ├── mex_w_times_x_symmetric.mexw64 ├── mex_w_times_x_symmetric.mexmaci64 ├── X2distances.m ├── computeW.m ├── discretisationEigenVectorData.m ├── imread_ncut.m ├── showmask.m ├── compileDir_simple.m ├── doog1.m ├── ncutW.m ├── ncutW_2.m ├── fft_filt_2.m ├── doog2.m ├── compute_relation.m ├── gaussian.m ├── NcutImage.m ├── make_filterbank_odd2.m ├── make_filterbank_even2.m ├── compute_relation2.m ├── computeEdges.m ├── ICgraph.m ├── demoNcutClustering.m ├── discretisation.m ├── mex_w_times_x_symmetric.cpp ├── demoNcutImage.m ├── README.txt ├── ncut.m ├── ncut_2.m ├── build_scene.m ├── quadedgep.m ├── spmtimesd.cpp ├── cimgnbmap.cpp ├── affinityic.cpp ├── sparsifyc.cpp ├── a_times_b_cmplx.cpp └── eigs_new.m ├── TSMCS_Enhanced Ensemble Clustering via Fast Propagation of Cluster-Wise Similarities.pdf ├── simxjac.m ├── NMImax.m ├── README.md ├── getECA.m ├── EnsembleGeneration.m ├── EnsembleGeneration_parallel.m ├── ECPCS_MC.m ├── getAllSegs.m ├── computePTS_II.m ├── ECPCS_HC.m ├── demo_1_ECPCS_MC.m └── demo_2_ECPCS_HC.m /data_BC.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huangdonghere/ECPCS/HEAD/data_BC.mat -------------------------------------------------------------------------------- /data_PD.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huangdonghere/ECPCS/HEAD/data_PD.mat -------------------------------------------------------------------------------- /Ncut/cimgnbmap.mexw64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huangdonghere/ECPCS/HEAD/Ncut/cimgnbmap.mexw64 -------------------------------------------------------------------------------- /Ncut/sparsifyc.mexw64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huangdonghere/ECPCS/HEAD/Ncut/sparsifyc.mexw64 -------------------------------------------------------------------------------- /Ncut/spmtimesd.mexw64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huangdonghere/ECPCS/HEAD/Ncut/spmtimesd.mexw64 -------------------------------------------------------------------------------- /Ncut/affinityic.mexw64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huangdonghere/ECPCS/HEAD/Ncut/affinityic.mexw64 -------------------------------------------------------------------------------- /Ncut/cimgnbmap.mexmaci64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huangdonghere/ECPCS/HEAD/Ncut/cimgnbmap.mexmaci64 -------------------------------------------------------------------------------- /Ncut/sparsifyc.mexmaci64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huangdonghere/ECPCS/HEAD/Ncut/sparsifyc.mexmaci64 -------------------------------------------------------------------------------- /Ncut/spmtimesd.mexmaci64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huangdonghere/ECPCS/HEAD/Ncut/spmtimesd.mexmaci64 -------------------------------------------------------------------------------- /Ncut/affinityic.mexmaci64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huangdonghere/ECPCS/HEAD/Ncut/affinityic.mexmaci64 -------------------------------------------------------------------------------- /Ncut/mex_w_times_x_symmetric.mexw64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huangdonghere/ECPCS/HEAD/Ncut/mex_w_times_x_symmetric.mexw64 -------------------------------------------------------------------------------- /Ncut/mex_w_times_x_symmetric.mexmaci64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huangdonghere/ECPCS/HEAD/Ncut/mex_w_times_x_symmetric.mexmaci64 -------------------------------------------------------------------------------- /TSMCS_Enhanced Ensemble Clustering via Fast Propagation of Cluster-Wise Similarities.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huangdonghere/ECPCS/HEAD/TSMCS_Enhanced Ensemble Clustering via Fast Propagation of Cluster-Wise Similarities.pdf -------------------------------------------------------------------------------- /Ncut/X2distances.m: -------------------------------------------------------------------------------- 1 | function distances = X2distances(X,Sigma); 2 | %Timothee Cour, 2004 3 | [n,k] = size(X); 4 | if nargin >= 2 5 | X = X*inv(sqrtm(Sigma)); 6 | end 7 | temp = sum(X.*X,2); 8 | temp = repmat(temp,1,n); 9 | distances = -2*X*X' + temp + temp'; -------------------------------------------------------------------------------- /Ncut/computeW.m: -------------------------------------------------------------------------------- 1 | function W = computeW(imageX,dataW,emag,ephase) 2 | % W = computeW(imageX,dataW,emag,ephase) 3 | % Timothee Cour, Stella Yu, Jianbo Shi, 2004. 4 | [p,q] = size(imageX); 5 | 6 | [w_i,w_j] = cimgnbmap([p,q],dataW.sampleRadius,dataW.sample_rate); 7 | 8 | W = affinityic(emag,ephase,w_i,w_j,max(emag(:)) * dataW.edgeVariance); 9 | W = W/max(W(:)); 10 | -------------------------------------------------------------------------------- /Ncut/discretisationEigenVectorData.m: -------------------------------------------------------------------------------- 1 | function Y = discretisationEigenVectorData(EigenVector) 2 | % Y = discretisationEigenVectorData(EigenVector) 3 | % 4 | % discretizes previously rotated eigenvectors in discretisation 5 | % Timothee Cour, Stella Yu, Jianbo Shi, 2004 6 | 7 | [n,k]=size(EigenVector); 8 | 9 | 10 | [Maximum,J]=max(EigenVector'); 11 | 12 | Y=sparse(1:n,J',1,n,k); 13 | -------------------------------------------------------------------------------- /Ncut/imread_ncut.m: -------------------------------------------------------------------------------- 1 | function I = imread_ncut(Image_file_name,nr,nc); 2 | % I = imread_ncut(Image_file_name); 3 | % 4 | % Timothee Cour, Stella Yu, Jianbo Shi, 2004. 5 | 6 | 7 | %% read image 8 | 9 | I = imread(Image_file_name); 10 | [Inr,Inc,nb] = size(I); 11 | 12 | if (nb>1), 13 | I =double(rgb2gray(I)); 14 | else 15 | I = double(I); 16 | end 17 | 18 | I = imresize(I,[nr, nc],'bicubic'); 19 | -------------------------------------------------------------------------------- /Ncut/showmask.m: -------------------------------------------------------------------------------- 1 | function RGB=showmask(V,M,display_flag); 2 | % showmask(V,M); 3 | % 4 | % M is a nonneg. mask 5 | % Jianbo Shi, 1997 6 | 7 | V=V-min(V(:)); 8 | V=V/max(V(:)); 9 | V=.25+0.75*V; %brighten things up a bit 10 | 11 | M=M-min(M(:)); 12 | M=M/max(M(:)); 13 | 14 | H=0.0+zeros(size(V)); 15 | S=M; 16 | RGB=hsv2rgb(H,S,V); 17 | 18 | %if nargin>2 19 | image(RGB) 20 | axis('image') 21 | %end 22 | -------------------------------------------------------------------------------- /Ncut/compileDir_simple.m: -------------------------------------------------------------------------------- 1 | function compileDir_simple(Cdir); 2 | if nargin<1 3 | Cdir=pwd; 4 | end 5 | 6 | files = dir(fullfile(Cdir,'*.cpp')); 7 | 8 | oldDir=pwd; 9 | cd(Cdir); 10 | for j=1:length(files) 11 | try 12 | % cm = sprintf('mex %s',files(j).name); 13 | cm = sprintf('mex -largeArrayDims %s',files(j).name); 14 | disp(cm); 15 | eval(cm); 16 | catch 17 | disp(lasterr); 18 | disp('IGNORE if the file is a C++ file which is not a mex file (ie without a mexFunction inside)'); 19 | end 20 | end 21 | 22 | cd(oldDir); -------------------------------------------------------------------------------- /Ncut/doog1.m: -------------------------------------------------------------------------------- 1 | function H=doog1(sig,r,th,N); 2 | % H=doog1(sig,r,th,N); 3 | % Serge Belongie 4 | 5 | no_pts=N; % no. of points in x,y grid 6 | 7 | [x,y]=meshgrid(-(N/2)+1/2:(N/2)-1/2,-(N/2)+1/2:(N/2)-1/2); 8 | 9 | phi=pi*th/180; 10 | sigy=sig; 11 | sigx=r*sig; 12 | R=[cos(phi) -sin(phi); sin(phi) cos(phi)]; 13 | C=R*diag([sigx,sigy])*R'; 14 | 15 | X=[x(:) y(:)]; 16 | 17 | Gb=gaussian(X,[0 0]',C); 18 | Gb=reshape(Gb,N,N); 19 | 20 | m=R*[0 sig]'; 21 | 22 | a=1; 23 | b=-1; 24 | 25 | % make odd-symmetric filter 26 | Ga=gaussian(X,m/2,C); 27 | Ga=reshape(Ga,N,N); 28 | Gb=rot90(Ga,2); 29 | H=a*Ga+b*Gb; 30 | 31 | -------------------------------------------------------------------------------- /simxjac.m: -------------------------------------------------------------------------------- 1 | % function s = simxjac(a,b) 2 | % 3 | % DESCRIPTION 4 | % computes extended Jaccard similarity between row objects in matrices a and b 5 | % 6 | % Copyright (c) 1998-2011 by Alexander Strehl 7 | 8 | function s = simxjac(a,b) 9 | 10 | if ~exist('b') 11 | b = a; 12 | end; 13 | 14 | n = size(a,1); 15 | m = size(b,1); 16 | d = size(a,2); 17 | if (d~=size(b,2)) 18 | disp('simxjac: data dimensions do not match'); 19 | return; 20 | end; 21 | 22 | temp = a *1* b'; 23 | asquared = sum((a.^2),2); 24 | bsquared = sum((b.^2),2); 25 | s = temp ./ ((asquared * ones(1,m)) + (ones(n,1) * bsquared') - temp); -------------------------------------------------------------------------------- /Ncut/ncutW.m: -------------------------------------------------------------------------------- 1 | function [NcutDiscrete,NcutEigenvectors,NcutEigenvalues] = ncutW(W,nbcluster); 2 | % [NcutDiscrete,NcutEigenvectors,NcutEigenvalues] = ncutW(W,nbcluster); 3 | % 4 | % Calls ncut to compute NcutEigenvectors and NcutEigenvalues of W with nbcluster clusters 5 | % Then calls discretisation to discretize the NcutEigenvectors into NcutDiscrete 6 | % Timothee Cour, Stella Yu, Jianbo Shi, 2004 7 | 8 | % compute continuous Ncut eigenvectors 9 | [NcutEigenvectors,NcutEigenvalues] = ncut(W,nbcluster); 10 | 11 | % compute discretize Ncut vectors 12 | [NcutDiscrete,NcutEigenvectors] =discretisation(NcutEigenvectors); 13 | 14 | 15 | NcutDiscrete = full(NcutDiscrete); -------------------------------------------------------------------------------- /Ncut/ncutW_2.m: -------------------------------------------------------------------------------- 1 | function [NcutDiscrete,NcutEigenvectors,NcutEigenvalues] = ncutW_2(W,nbcluster); 2 | % [NcutDiscrete,NcutEigenvectors,NcutEigenvalues] = ncutW(W,nbcluster); 3 | % 4 | % Calls ncut to compute NcutEigenvectors and NcutEigenvalues of W with nbcluster clusters 5 | % Then calls discretisation to discretize the NcutEigenvectors into NcutDiscrete 6 | % Timothee Cour, Stella Yu, Jianbo Shi, 2004 7 | 8 | % compute continuous Ncut eigenvectors 9 | [NcutEigenvectors,NcutEigenvalues] = ncut_2(W,nbcluster); 10 | 11 | % compute discretize Ncut vectors 12 | [NcutDiscrete,NcutEigenvectors] =discretisation(NcutEigenvectors); 13 | 14 | 15 | NcutDiscrete = full(NcutDiscrete); -------------------------------------------------------------------------------- /Ncut/fft_filt_2.m: -------------------------------------------------------------------------------- 1 | function FI=fft_filt_2(V,FB,sf); 2 | % FI=fft_filt_2(V,FB,sf); 3 | % fft-based filtering 4 | % requires image to be called "V" 5 | % and filters to be in FB 6 | % sf is the subsampling factor 7 | % 8 | % FI is the result 9 | % Jianbo Shi, 1997 10 | 11 | [M1,M2,N3]=size(FB); 12 | % prepare FFT of image for filtering 13 | [N1,N2]=size(V); 14 | I=zeros(size(V)+[M1-1 M2-1]); 15 | I(1:N1,1:N2)=V; 16 | N1s=length(1:sf:N1); 17 | N2s=length(1:sf:N2); 18 | IF=fft2(I); 19 | FI=zeros(N1s,N2s,N3); 20 | 21 | % apply filters 22 | for n=1:N3; 23 | f=rot90(FB(:,:,n),2); 24 | fF=fft2(f,N1+M1-1,N2+M2-1); 25 | IfF=IF.*fF; 26 | If=real(ifft2(IfF)); 27 | If=If(ceil((M1+1)/2):ceil((M1+1)/2)+N1-1,ceil((M2+1)/2):ceil((M2+1)/2)+N2-1); 28 | FI(:,:,n)=If(1:sf:N1,1:sf:N2); 29 | end 30 | 31 | -------------------------------------------------------------------------------- /Ncut/doog2.m: -------------------------------------------------------------------------------- 1 | function G=doog2(sig,r,th,N); 2 | % G=doog2(sig,r,th,N); 3 | % Make difference of offset gaussians kernel 4 | % theta is in degrees 5 | % (see Malik & Perona, J. Opt. Soc. Amer., 1990) 6 | % 7 | % Example: 8 | % >> imagesc(doog2(1,12,0,64,1)) 9 | % >> colormap(gray) 10 | % 11 | % Serge Belongie 12 | 13 | 14 | no_pts=N; % no. of points in x,y grid 15 | 16 | [x,y]=meshgrid(-(N/2)+1/2:(N/2)-1/2,-(N/2)+1/2:(N/2)-1/2); 17 | 18 | phi=pi*th/180; 19 | sigy=sig; 20 | sigx=r*sig; 21 | R=[cos(phi) -sin(phi); sin(phi) cos(phi)]; 22 | C=R*diag([sigx,sigy])*R'; 23 | 24 | X=[x(:) y(:)]; 25 | 26 | Gb=gaussian(X,[0 0]',C); 27 | Gb=reshape(Gb,N,N); 28 | 29 | m=R*[0 sig]'; 30 | Ga=gaussian(X,m,C); 31 | Ga=reshape(Ga,N,N); 32 | Gc=rot90(Ga,2); 33 | 34 | a=-1; 35 | b=2; 36 | c=-1; 37 | 38 | G = a*Ga + b*Gb + c*Gc; 39 | 40 | -------------------------------------------------------------------------------- /Ncut/compute_relation.m: -------------------------------------------------------------------------------- 1 | function [W,distances] = compute_relation(data,scale_sig,order) 2 | % 3 | % [W,distances] = compute_relation(data,scale_sig) 4 | % Input: data= Feature_dimension x Num_data 5 | % ouput: W = pair-wise data similarity matrix 6 | % Dist = pair-wise Euclidean distance 7 | % 8 | % 9 | % Jianbo Shi, 1997 10 | 11 | 12 | distances = zeros(length(data),length(data)); 13 | for j = 1:length(data), 14 | distances(j,:) = (sqrt((data(1,:)-data(1,j)).^2 +... 15 | (data(2,:)-data(2,j)).^2)); 16 | end 17 | 18 | % distances = X2distances(data'); 19 | 20 | if (~exist('scale_sig')), 21 | scale_sig = 0.05*max(distances(:)); 22 | end 23 | 24 | if (~exist('order')), 25 | order = 2; 26 | end 27 | 28 | tmp = (distances/scale_sig).^order; 29 | 30 | W = exp(-tmp); 31 | 32 | -------------------------------------------------------------------------------- /Ncut/gaussian.m: -------------------------------------------------------------------------------- 1 | function p=gaussian(x,m,C); 2 | % p=gaussian(x,m,C); 3 | % 4 | % Evaluate the multi-variate density with mean vector m and covariance 5 | % matrix C for the input vector x. 6 | % 7 | % p=gaussian(X,m,C); 8 | % 9 | % Vectorized version: Here X is a matrix of column vectors, and p is 10 | % a vector of probabilities for each vector. 11 | % Jianbo Shi, 1997 12 | d=length(m); 13 | 14 | if size(x,1)~=d 15 | x=x'; 16 | end 17 | N=size(x,2); 18 | 19 | detC = det(C); 20 | if rcond(C) log). 5 | 6 | assert(numel(x) == numel(y)); 7 | n = numel(x); 8 | x = reshape(x,1,n); 9 | y = reshape(y,1,n); 10 | 11 | l = min(min(x),min(y)); 12 | x = x-l+1; 13 | y = y-l+1; 14 | k = max(max(x),max(y)); 15 | 16 | idx = 1:n; 17 | Mx = sparse(idx,x,1,n,k,n); 18 | My = sparse(idx,y,1,n,k,n); 19 | Pxy = nonzeros(Mx'*My/n); %joint distribution of x and y 20 | Hxy = -dot(Pxy,log(Pxy+eps)); 21 | 22 | Px = mean(Mx,1); 23 | Py = mean(My,1); 24 | 25 | % entropy of Py and Px 26 | Hx = -dot(Px,log(Px+eps)); 27 | Hy = -dot(Py,log(Py+eps)); 28 | 29 | % mutual information 30 | MI = Hx + Hy - Hxy; 31 | 32 | % maximum normalized mutual information 33 | NMImax = MI/max(Hx,Hy); 34 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ECPCS 2 | 3 | This repository provides the Matlab source code for the `Ensemble Clustering by Propagating Cluster-wise Similarities (ECPCS)` approach, which is further developed into two ensemble clustering algorithms, i.e., `ECPCS with hierarchical consensus function (ECPCS-HC)` and `ECPCS with with meta-cluster based consensus function (ECPCS-MC)`. 4 | 5 | If you find this repository helpful for your research, please cite the paper below. 6 | 7 | ``` 8 | Dong Huang, Chang-Dong Wang, Hongxing Peng, Jianhuang Lai, and Chee-Keong Kwoh. 9 | Enhanced Ensemble Clustering via Fast Propagation of Cluster-wise Similarities. 10 | IEEE Transactions on Systems, Man, and Cybernetics: Systems, 2021, 51(1), pp.508-520. 11 | DOI: https://doi.org/10.1109/TSMC.2018.2876202 12 | ``` 13 | 14 | Don't hesitate to contact me if you have any questions regarding this work. 15 | Email: huangdonghere at gmail dot com 16 | Website: https://www.researchgate.net/publication/328581758 17 | -------------------------------------------------------------------------------- /Ncut/make_filterbank_odd2.m: -------------------------------------------------------------------------------- 1 | function FB = make_filterbank(num_ori,filter_scales,wsz,enlong) 2 | % 3 | % F = make_filterbank(num_ori,num_scale,wsz) 4 | % Jianbo Shi, 1997 5 | 6 | if nargin<4, 7 | enlong = 3; 8 | end 9 | 10 | enlong = enlong*2; 11 | 12 | % definine filterbank 13 | %num_ori=6; 14 | %num_scale=3; 15 | 16 | num_scale = length(filter_scales); 17 | 18 | M1=wsz; % size in pixels 19 | M2=M1; 20 | 21 | ori_incr=180/num_ori; 22 | ori_offset=ori_incr/2; % helps with equalizing quantiz. error across filter set 23 | 24 | FB=zeros(M1,M2,num_ori,num_scale); 25 | 26 | 27 | % elongated filter set 28 | counter = 1; 29 | 30 | for m=1:num_scale 31 | for n=1:num_ori 32 | % r=12 here is equivalent to Malik's r=3; 33 | f=doog1(filter_scales(m),enlong,ori_offset+(n-1)*ori_incr,M1); 34 | FB(:,:,n,m)=f; 35 | end 36 | end 37 | 38 | FB=reshape(FB,M1,M2,num_scale*num_ori); 39 | total_num_filt=size(FB,3); 40 | 41 | for j=1:total_num_filt, 42 | F = FB(:,:,j); 43 | a = sum(sum(abs(F))); 44 | FB(:,:,j) = FB(:,:,j)/a; 45 | end 46 | 47 | -------------------------------------------------------------------------------- /Ncut/make_filterbank_even2.m: -------------------------------------------------------------------------------- 1 | function FB = make_filterbank(num_ori,filter_scales,wsz,enlong) 2 | % 3 | % F = make_filterbank(num_ori,num_scale,wsz) 4 | % Jianbo Shi, 1997 5 | 6 | 7 | if nargin<4, 8 | enlong = 3; 9 | end 10 | 11 | enlong = 2*enlong; 12 | 13 | % definine filterbank 14 | %num_ori=6; 15 | %num_scale=3; 16 | 17 | num_scale = length(filter_scales); 18 | 19 | M1=wsz; % size in pixels 20 | M2=M1; 21 | 22 | ori_incr=180/num_ori; 23 | ori_offset=ori_incr/2; % helps with equalizing quantiz. error across filter set 24 | 25 | FB=zeros(M1,M2,num_ori,num_scale); 26 | 27 | % elongated filter set 28 | counter = 1; 29 | 30 | for m=1:num_scale 31 | for n=1:num_ori 32 | % r=12 here is equivalent to Malik's r=3; 33 | f=doog2(filter_scales(m),enlong,ori_offset+(n-1)*ori_incr,M1); 34 | FB(:,:,n,m)=f; 35 | end 36 | end 37 | 38 | FB=reshape(FB,M1,M2,num_scale*num_ori); 39 | total_num_filt=size(FB,3); 40 | 41 | for j=1:total_num_filt, 42 | F = FB(:,:,j); 43 | a = sum(sum(abs(F))); 44 | FB(:,:,j) = FB(:,:,j)/a; 45 | end 46 | 47 | -------------------------------------------------------------------------------- /Ncut/compute_relation2.m: -------------------------------------------------------------------------------- 1 | function [A,B] = compute_relation2(data,scale_sig,order) 2 | % 3 | % [W,Dist] = compute_relation(data,scale_sig) 4 | % Input: data= Feature_dimension x Num_data 5 | % ouput: W = pair-wise data similarity matrix 6 | % Dist = pair-wise Euclidean distance 7 | % 8 | % 9 | % Jianbo Shi, 1997 10 | 11 | if (~exist('order')), 12 | order = 2; 13 | % order = 1; 14 | end 15 | 16 | n = size(data,2); 17 | 18 | B = zeros(n); 19 | for j = 1:n 20 | B(:,j) = (sqrt((data(1,:)-data(1,j)).^2 +... 21 | (data(2,:)-data(2,j)).^2))'; 22 | end 23 | 24 | if (~exist('scale_sig')), 25 | scale_sig = 0.05*max(B(:)); 26 | % scale_sig = 0.04*max(B(:)); 27 | end 28 | 29 | % kNN = 5; 30 | % B2 = B; 31 | % for j=1:n 32 | % [ignore,ind] = sort(B(:,j)); 33 | % B2(ind(kNN+1:end),j) = Inf; 34 | % B2(ind(1:kNN),j) = B(ind(1:kNN),j) / max(B(ind(1:kNN),j)) * 0.5; 35 | % end 36 | % scale_sig = 1; 37 | % B = min(B2,B2');%(B+B')/2; 38 | 39 | tmp = (B/scale_sig).^order; 40 | 41 | A = exp(-tmp); 42 | 43 | 44 | -------------------------------------------------------------------------------- /Ncut/computeEdges.m: -------------------------------------------------------------------------------- 1 | function edgemap = computeEdges(imageX,parametres,threshold) 2 | % edgemap = computeEdges(imageX,parametres,threshold) 3 | % 4 | % computes the edge in imageX with parameters parametres and threshold 5 | % Timothee Cour, Stella Yu, Jianbo Shi, 2004. 6 | 7 | [ex,ey,egx,egy,eg_par,eg_th,emag,ephase , g ] = quadedgep(imageX,parametres,threshold); 8 | % example : [ex,ey,egx,egy,eg_par,eg_th,emag,ephase] = quadedgep(imageX,[4,3,30,3],0.05); 9 | 10 | % [emagTrie,eindex] = sort(emag); 11 | 12 | %edges3 = sparse(floor(ex),floor(ey),(egx.^2+egy.^2).^(1/2),size(imageX,2),size(imageX,1))'; 13 | 14 | try 15 | edges2 = emag .* edge(imageX,'canny') ; 16 | %edges2 = emag .* edge(imageX,'sobel') ; 17 | catch 18 | edges2 = 0 * emag; 19 | end 20 | 21 | edges2 = edges2 .* (edges2 > threshold); 22 | egx1 = g(:,:,1); 23 | egy1 = g(:,:,2); 24 | eindex = find(edges2); 25 | [ey,ex,values] = find(edges2); 26 | 27 | egx = egx1(eindex); 28 | egy = egy1(eindex); 29 | 30 | edgemap.eindex = eindex; 31 | edgemap.values = values; 32 | edgemap.x = ex; 33 | edgemap.y = ey; 34 | edgemap.gx = egx; 35 | edgemap.gy = egy; 36 | edgemap.emag = emag; 37 | edgemap.ephase = ephase; 38 | edgemap.imageEdges = edges2; 39 | -------------------------------------------------------------------------------- /Ncut/ICgraph.m: -------------------------------------------------------------------------------- 1 | function [W,imageEdges] = ICgraph(I,dataW,dataEdgemap); 2 | % [W,imageEdges] = ICgraph(I,dataW,dataEdgemap); 3 | % Input: 4 | % I = gray-level image 5 | % optional parameters: 6 | % dataW.sampleRadius=10; 7 | % dataW.sample_rate=0.3; 8 | % dataW.edgeVariance = 0.1; 9 | % 10 | % dataEdgemap.parametres=[4,3, 21,3];%[number of filter orientations, number of scales, filter size, elongation] 11 | % dataEdgemap.threshold=0.02; 12 | % 13 | % Output: 14 | % W: npixels x npixels similarity matrix based on Intervening Contours 15 | % imageEdges: image showing edges extracted in the image 16 | % 17 | % Timothee Cour, Stella Yu, Jianbo Shi, 2004. 18 | 19 | 20 | 21 | [p,q] = size(I); 22 | 23 | if (nargin< 2) | isempty(dataW), 24 | dataW.sampleRadius=10; 25 | dataW.sample_rate=0.3; 26 | dataW.edgeVariance = 0.1; 27 | end 28 | 29 | if (nargin<3) | isempty(dataEdgemap), 30 | dataEdgemap.parametres=[4,3, 21,3];%[number of filter orientations, number of scales, filter size, elongation] 31 | dataEdgemap.threshold=0.02; 32 | end 33 | 34 | 35 | edgemap = computeEdges(I,dataEdgemap.parametres,dataEdgemap.threshold); 36 | imageEdges = edgemap.imageEdges; 37 | W = computeW(I,dataW,edgemap.emag,edgemap.ephase); 38 | -------------------------------------------------------------------------------- /Ncut/demoNcutClustering.m: -------------------------------------------------------------------------------- 1 | function demoNcutClustering; 2 | % demoNcutClustering 3 | % 4 | % demo for NcutClustering 5 | % also initialize matlab paths to subfolders 6 | % Timothee Cour, Stella Yu, Jianbo Shi, 2004. 7 | 8 | disp('Ncut Clustering demo'); 9 | 10 | %% make up a point data set 11 | caseid = 2;%3 12 | [data,size_cluster] = build_scene(caseid); 13 | figure(1);clf; 14 | plot(data(1,:),data(2,:),'ks', 'MarkerFaceColor','k','MarkerSize',5); axis image; hold on; 15 | 16 | disp('This is the input data points to be clustered, press Enter to continue...'); 17 | pause; 18 | 19 | disp('Compute clustering...'); 20 | 21 | % compute similarity matrix 22 | [W,Dist] = compute_relation(data); 23 | 24 | % clustering graph in 25 | nbCluster = 4; 26 | tic; 27 | [NcutDiscrete,NcutEigenvectors,NcutEigenvalues] = ncutW(W,nbCluster); 28 | disp(['The computation took ' num2str(toc) ' seconds']); 29 | figure(3); 30 | plot(NcutEigenvectors); 31 | 32 | % display clustering result 33 | cluster_color = ['rgbmyc']; 34 | figure(2);clf; 35 | for j=1:nbCluster, 36 | id = find(NcutDiscrete(:,j)); 37 | plot(data(1,id),data(2,id),[cluster_color(j),'s'], 'MarkerFaceColor',cluster_color(j),'MarkerSize',5); hold on; 38 | end 39 | hold off; axis image; 40 | disp('This is the clustering result'); 41 | disp('The demo is finished.'); 42 | -------------------------------------------------------------------------------- /getECA.m: -------------------------------------------------------------------------------- 1 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2 | % If you find the code useful for your research, please cite the paper % 3 | % below: % 4 | % % 5 | % D. Huang, C.-D. Wang, H. Peng, J. Lai, & C.-K. Kwoh. "Enhanced Ensemble % 6 | % Clustering via Fast Propagation of Cluster-wise Similarities."To appear % 7 | % in IEEE Transactions on Systems, Man, and Cybernetics: Systems. % 8 | % DOI: 10.1109/TSMC.2018.2876202 % 9 | % % 10 | % The code has been tested in Matlab R2016a and Matlab R2016b. % 11 | % % 12 | % www.researchgate.net/publication/328581758 % 13 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 14 | 15 | function ECA = getECA(bcs,Sim) 16 | % Compute the enhanced co-association (ECA) matrix. 17 | % Dong Huang. Apr. 18, 2018. 18 | 19 | [N,M] = size(bcs); 20 | ECA = zeros(N,N); 21 | Sim = Sim-diag(diag(Sim))+diag(ones(size(Sim,1),1)); 22 | 23 | for m = 1:M 24 | ECA = ECA + Sim(bcs(:,m),bcs(:,m)); 25 | end 26 | 27 | ECA = ECA/M; -------------------------------------------------------------------------------- /Ncut/discretisation.m: -------------------------------------------------------------------------------- 1 | function [EigenvectorsDiscrete,EigenVectors]=discretisation(EigenVectors) 2 | % 3 | % EigenvectorsDiscrete=discretisation(EigenVectors) 4 | % 5 | % Input: EigenVectors = continuous Ncut vector, size = ndata x nbEigenvectors 6 | % Output EigenvectorsDiscrete = discrete Ncut vector, size = ndata x nbEigenvectors 7 | % 8 | % Timothee Cour, Stella Yu, Jianbo Shi, 2004 9 | 10 | [n,k]=size(EigenVectors); 11 | 12 | vm = sqrt(sum(EigenVectors.*EigenVectors,2)); 13 | EigenVectors = EigenVectors./repmat(vm,1,k); 14 | 15 | R=zeros(k); 16 | R(:,1)=EigenVectors(1+round(rand(1)*(n-1)),:)'; 17 | c=zeros(n,1); 18 | for j=2:k 19 | c=c+abs(EigenVectors*R(:,j-1)); 20 | [minimum,i]=min(c); 21 | R(:,j)=EigenVectors(i,:)'; 22 | end 23 | 24 | lastObjectiveValue=0; 25 | exitLoop=0; 26 | nbIterationsDiscretisation = 0; 27 | nbIterationsDiscretisationMax = 20;%voir 28 | while exitLoop== 0 29 | nbIterationsDiscretisation = nbIterationsDiscretisation + 1 ; 30 | EigenvectorsDiscrete = discretisationEigenVectorData(EigenVectors*R); 31 | [U,S,V] = svd(EigenvectorsDiscrete'*EigenVectors,0); 32 | NcutValue=2*(n-trace(S)); 33 | 34 | if abs(NcutValue-lastObjectiveValue) < eps | nbIterationsDiscretisation > nbIterationsDiscretisationMax 35 | exitLoop=1; 36 | else 37 | lastObjectiveValue = NcutValue; 38 | R=V*U'; 39 | end 40 | end -------------------------------------------------------------------------------- /EnsembleGeneration.m: -------------------------------------------------------------------------------- 1 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2 | % If you find the code useful for your research, please cite the paper % 3 | % below: % 4 | % % 5 | % D. Huang, C.-D. Wang, H. Peng, J. Lai, & C.-K. Kwoh. "Enhanced Ensemble % 6 | % Clustering via Fast Propagation of Cluster-wise Similarities."To appear % 7 | % in IEEE Transactions on Systems, Man, and Cybernetics: Systems. % 8 | % DOI: 10.1109/TSMC.2018.2876202 % 9 | % % 10 | % The code has been tested in Matlab R2016a and Matlab R2016b. % 11 | % % 12 | % www.researchgate.net/publication/328581758 % 13 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 14 | 15 | function baseCls = EnsembleGeneration(fea, M, lowerK, upperK) 16 | % This function generates M base clusterings by k-means. 17 | % Each base clustering is generated by k-means with the cluster number randomly selected in [lowerK, upperK]. 18 | 19 | N = size(fea,1); 20 | 21 | clsNums = randi([lowerK, upperK],M,1); 22 | 23 | baseCls = zeros(N,M); 24 | for i = 1:M 25 | baseCls(:,i) = kmeans(fea, clsNums(i)); 26 | end 27 | -------------------------------------------------------------------------------- /EnsembleGeneration_parallel.m: -------------------------------------------------------------------------------- 1 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2 | % If you find the code useful for your research, please cite the paper % 3 | % below: % 4 | % % 5 | % D. Huang, C.-D. Wang, H. Peng, J. Lai, & C.-K. Kwoh. "Enhanced Ensemble % 6 | % Clustering via Fast Propagation of Cluster-wise Similarities."To appear % 7 | % in IEEE Transactions on Systems, Man, and Cybernetics: Systems. % 8 | % DOI: 10.1109/TSMC.2018.2876202 % 9 | % % 10 | % The code has been tested in Matlab R2016a and Matlab R2016b. % 11 | % % 12 | % www.researchgate.net/publication/328581758 % 13 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 14 | 15 | function baseCls = EnsembleGeneration_parallel(fea, M, lowerK, upperK) 16 | % This function generates M base clusterings by k-means. 17 | % Each base clustering is generated by k-means with the cluster number randomly selected in [lowerK, upperK]. 18 | 19 | N = size(fea,1); 20 | 21 | clsNums = randi([lowerK, upperK],M,1); 22 | 23 | baseCls = zeros(N,M); 24 | parfor i = 1:M % This is a paralleled version 25 | baseCls(:,i) = kmeans(fea, clsNums(i)); 26 | end 27 | -------------------------------------------------------------------------------- /Ncut/mex_w_times_x_symmetric.cpp: -------------------------------------------------------------------------------- 1 | /*================================================================ 2 | * mex_w_times_x_symmetric.c = used by ncuthard2.m in eigensolver. 3 | * 4 | * Examples: 5 | * mex_w_times_x_c_symmetric(x,triu(A)) = A*x; 6 | * A is sparse and symmetric, but x is full 7 | * 8 | * Timothee Cour, Oct 12, 2003. 9 | 10 | % test sequence: 11 | m=100; 12 | n=50; 13 | x=rand(n,1); 14 | A=sprand(m,n,0.01); 15 | 16 | y2 = mex_w_times_x_c_symmetric(x,triu(A)); 17 | y1=A*x; 18 | max(abs(y1-y2)) 19 | *=================================================================*/ 20 | 21 | # include "math.h" 22 | # include "mex.h" 23 | # include "a_times_b_cmplx.cpp" 24 | /*# include "a_times_b.c"*/ 25 | 26 | 27 | void mexFunction( 28 | int nargout, 29 | mxArray *out[], 30 | int nargin, 31 | const mxArray *in[] 32 | ) 33 | { 34 | int np, nc; 35 | mwIndex*ir, *jc; 36 | double *x, *y, *pr; 37 | 38 | if (nargin < 2) {//voir 39 | mexErrMsgTxt("Four input arguments required !"); 40 | } 41 | if (nargout>1) { 42 | mexErrMsgTxt("Too many output arguments."); 43 | } 44 | 45 | x = mxGetPr(in[0]); 46 | pr = mxGetPr(in[1]); 47 | ir = mxGetIr(in[1]); 48 | jc = mxGetJc(in[1]); 49 | 50 | np = mxGetM(in[1]); 51 | nc = mxGetN(in[1]); 52 | 53 | out[0] = mxCreateDoubleMatrix(np,1,mxREAL); 54 | y = mxGetPr(out[0]); 55 | 56 | CSRsymm_VecMult_CAB_double(np,nc,pr,ir,jc,x,y); 57 | } 58 | -------------------------------------------------------------------------------- /Ncut/demoNcutImage.m: -------------------------------------------------------------------------------- 1 | function demoNcutImage; 2 | % demoNcutImage 3 | % 4 | % demo for NcutImage 5 | % also initialize matlab paths to subfolders 6 | % Timothee Cour, Stella Yu, Jianbo Shi, 2004. 7 | 8 | disp('Ncut Image Segmentation demo'); 9 | 10 | %% read image, change color image to brightness image, resize to 160x160 11 | I = imread_ncut('jpg_images/3.jpg',160,160); 12 | 13 | %% display the image 14 | figure(1);clf; imagesc(I);colormap(gray);axis off; 15 | disp('This is the input image to segment, press Enter to continue...'); 16 | pause; 17 | 18 | %% compute the edges imageEdges, the similarity matrix W based on 19 | %% Intervening Contours, the Ncut eigenvectors and discrete segmentation 20 | nbSegments = 5; 21 | disp('computing Ncut eigenvectors ...'); 22 | tic; 23 | [SegLabel,NcutDiscrete,NcutEigenvectors,NcutEigenvalues,W,imageEdges]= NcutImage(I,nbSegments); 24 | disp(['The computation took ' num2str(toc) ' seconds on the ' num2str(size(I,1)) 'x' num2str(size(I,2)) ' image']); 25 | 26 | 27 | %% display the edges 28 | figure(2);clf; imagesc(imageEdges); axis off 29 | disp('This is the edges computed, press Enter to continue...'); 30 | pause; 31 | 32 | %% display the segmentation 33 | figure(3);clf 34 | bw = edge(SegLabel,0.01); 35 | J1=showmask(I,imdilate(bw,ones(2,2))); imagesc(J1);axis off 36 | disp('This is the segmentation, press Enter to continue...'); 37 | pause; 38 | 39 | %% display Ncut eigenvectors 40 | figure(4);clf;set(gcf,'Position',[100,500,200*(nbSegments+1),200]); 41 | [nr,nc,nb] = size(I); 42 | for i=1:nbSegments 43 | subplot(1,nbSegments,i); 44 | imagesc(reshape(NcutEigenvectors(:,i) , nr,nc));axis('image');axis off; 45 | end 46 | disp('This is the Ncut eigenvectors...'); 47 | disp('The demo is finished.'); 48 | 49 | -------------------------------------------------------------------------------- /ECPCS_MC.m: -------------------------------------------------------------------------------- 1 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2 | % This is the code for ECPCS-MC, which is an ensemble clustering algorithm% 3 | % proposed in the following paper: % 4 | % % 5 | % D. Huang, C.-D. Wang, H. Peng, J. Lai, & C.-K. Kwoh. "Enhanced Ensemble % 6 | % Clustering via Fast Propagation of Cluster-wise Similarities."To appear % 7 | % in IEEE Transactions on Systems, Man, and Cybernetics: Systems. % 8 | % DOI: 10.1109/TSMC.2018.2876202 % 9 | % % 10 | % The code has been tested in Matlab R2016a and Matlab R2016b. % 11 | % % 12 | % www.researchgate.net/publication/328581758 % 13 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 14 | 15 | function Label = ECPCS_MC(baseCls, K, t) 16 | % Dong Huang. Sep. 28, 2018. 17 | 18 | if nargin < 3 19 | t = 20; 20 | end 21 | 22 | [N,M] = size(baseCls); 23 | 24 | [bcs, baseClsSegs] = getAllSegs(baseCls); 25 | clsSim = full(simxjac(baseClsSegs)); % Build the cluster similarity matrix by Jaccard coefficient. 26 | clsSimRW = computePTS_II(clsSim, t); % Perform random walks and obtain a new cluster-wise similarity matrix. 27 | 28 | % Meta-clustering 29 | clsL = ncutW_2(clsSimRW, K); 30 | for j = 2:size(clsL,2) 31 | clsL(:,j) = clsL(:,j) * j; 32 | end 33 | clsLabel = sum(clsL'); 34 | clsLabel_cum = zeros(K, N); 35 | for i=1:max(clsLabel), 36 | matched_clusters = find(clsLabel==i); 37 | clsLabel_cum(i,:) = mean(baseClsSegs(matched_clusters,:),1); 38 | end; 39 | [~,Label]=max(clsLabel_cum); % Majority voting 40 | 41 | 42 | -------------------------------------------------------------------------------- /getAllSegs.m: -------------------------------------------------------------------------------- 1 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2 | % If you find the code useful for your research, please cite the paper % 3 | % below: % 4 | % % 5 | % D. Huang, C.-D. Wang, H. Peng, J. Lai, & C.-K. Kwoh. "Enhanced Ensemble % 6 | % Clustering via Fast Propagation of Cluster-wise Similarities."To appear % 7 | % in IEEE Transactions on Systems, Man, and Cybernetics: Systems. % 8 | % DOI: 10.1109/TSMC.2018.2876202 % 9 | % % 10 | % The code has been tested in Matlab R2016a and Matlab R2016b. % 11 | % % 12 | % www.researchgate.net/publication/328581758 % 13 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 14 | 15 | function [bcs, baseClsSegs] = getAllSegs(baseCls) 16 | % Dong Huang. 19 April, 2013. 17 | % Optimized for speed by Nejc Ilc, 5 June 2014 18 | 19 | [N,nBC] = size(baseCls); 20 | % n: the number of data points. 21 | % nBase: the number of base clusterings. 22 | % nCls: the number of clusters (in all base clusterings). 23 | 24 | 25 | bcs = baseCls; 26 | nClsOrig = max(bcs,[],1); 27 | C = cumsum(nClsOrig); 28 | bcs = bsxfun(@plus, bcs,[0 C(1:end-1)]); 29 | nCls = nClsOrig(end)+C(end-1); 30 | baseClsSegs = zeros(nCls,N); 31 | 32 | for i=1:nBC 33 | if i == 1 34 | startK = 1; 35 | else 36 | startK = (C(i-1)+1); 37 | end 38 | endK = C(i); 39 | searchVec = startK:endK; 40 | F = bsxfun(@eq,bcs(:,i),searchVec); 41 | baseClsSegs(searchVec,:) = F'; 42 | end 43 | 44 | 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /computePTS_II.m: -------------------------------------------------------------------------------- 1 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2 | % If you find the code useful for your research, please cite the paper % 3 | % below: % 4 | % % 5 | % D. Huang, C.-D. Wang, H. Peng, J. Lai, & C.-K. Kwoh. "Enhanced Ensemble % 6 | % Clustering via Fast Propagation of Cluster-wise Similarities."To appear % 7 | % in IEEE Transactions on Systems, Man, and Cybernetics: Systems. % 8 | % DOI: 10.1109/TSMC.2018.2876202 % 9 | % % 10 | % The code has been tested in Matlab R2016a and Matlab R2016b. % 11 | % % 12 | % www.researchgate.net/publication/328581758 % 13 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 14 | 15 | function [newS] = computePTS_II(S, paraT) 16 | % This function performs random walk on S, and obtains a new similarity 17 | % matrix by comparing the random walk trajectories starting from different nodes. 18 | % 19 | % Input: 20 | % S: the similarity matrix (of a graph) 21 | % paraT: the number of steps of random walk 22 | % Output: 23 | % newS: the newly obtained similarity matrix 24 | % 25 | % Dong Huang. Sep. 28, 2018. 26 | 27 | 28 | N = size(S,1); 29 | 30 | 31 | for i = 1:size(S,1), S(i,i)=0; end 32 | 33 | rowSum = sum(S,2); 34 | rowSums = repmat(rowSum, 1, N); 35 | rowSums(rowSums==0)=-1;% find and label the isolated point 36 | P = S./rowSums; % transition probability. 37 | P(P<0)=0; % remove the isolated point. 38 | 39 | %% Compute PTS 40 | tmpP = P; 41 | inProdP = P*P'; 42 | for ii = 1:(paraT-1) 43 | tmpP = tmpP*P; 44 | inProdP = inProdP + tmpP*tmpP'; 45 | end 46 | inProdPii = repmat(diag(inProdP), 1, N); 47 | inProdPjj = inProdPii'; 48 | newS = inProdP./sqrt(inProdPii.*inProdPjj); 49 | 50 | sr = sum(P'); 51 | isolatedIdx = find(sr<10e-10); 52 | if numel(isolatedIdx)>0 53 | newS(isolatedIdx,:) = 0; 54 | newS(:,isolatedIdx) = 0; 55 | end -------------------------------------------------------------------------------- /ECPCS_HC.m: -------------------------------------------------------------------------------- 1 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2 | % This is the code for ECPCS-HC, which is an ensemble clustering algorithm% 3 | % proposed in the following paper: % 4 | % % 5 | % D. Huang, C.-D. Wang, H. Peng, J. Lai, & C.-K. Kwoh. "Enhanced Ensemble % 6 | % Clustering via Fast Propagation of Cluster-wise Similarities."To appear % 7 | % in IEEE Transactions on Systems, Man, and Cybernetics: Systems. % 8 | % DOI: 10.1109/TSMC.2018.2876202 % 9 | % % 10 | % The code has been tested in Matlab R2016a and Matlab R2016b. % 11 | % % 12 | % www.researchgate.net/publication/328581758 % 13 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 14 | 15 | function Label = ECPCS_HC(baseCls, K, t) 16 | % Dong Huang. Sep. 28, 2018. 17 | 18 | if nargin < 3 19 | t = 20; 20 | end 21 | 22 | [bcs, baseClsSegs] = getAllSegs(baseCls); 23 | clsSim = full(simxjac(baseClsSegs)); % Build the cluster similarity matrix by Jaccard coefficient. 24 | clsSimRW = computePTS_II(clsSim, t); % Perform random walks and obtain a new cluster-wise similarity matrix. 25 | 26 | ECA = getECA(bcs,clsSimRW); 27 | Label = runHC(ECA, K); 28 | 29 | 30 | 31 | function Label = runHC(S, ks) 32 | % Input: the similarity matrix 33 | % and the numbers of clusters. 34 | % Output: the clustering result. 35 | 36 | N = size(S,1); 37 | 38 | d = stod(S); clear S %convert similarity matrix to distance vector 39 | % average linkage 40 | Zal = linkage(d,'average'); clear d 41 | 42 | Label = zeros(N,numel(ks)); 43 | for iK = 1:numel(ks) 44 | Label(:,iK) = cluster(Zal,'maxclust',ks(iK)); 45 | end 46 | 47 | function d = stod(S) 48 | % Dong Huang. Apr. 19, 2018. 49 | 50 | N = size(S,1); 51 | s = zeros(1,(1+N-1)*(N-1)/2); 52 | nextIdx = 1; 53 | for a = 1:N-1 %change matrix's format to be input of linkage fn 54 | s(nextIdx:nextIdx+(N-a-1)) = S(a,[a+1:end]); 55 | nextIdx = nextIdx + N - a; 56 | end 57 | d = 1 - s; 58 | 59 | 60 | -------------------------------------------------------------------------------- /Ncut/README.txt: -------------------------------------------------------------------------------- 1 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2 | % Normalized Cut Segmentation Code % 3 | % % 4 | % Timothee Cour (INRIA), Stella Yu (Berkeley), Jianbo Shi (UPENN) % 5 | % % 6 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 7 | 8 | License 9 | This software is made publicly for research use only. It may be modified and redistributed under the terms of the GNU General Public License. 10 | 11 | Citation 12 | Please cite the following if you plan to use the code in your own work: 13 | * Normalized Cuts and Image Segmentation, Jianbo Shi and Jitendra Malik, IEEE Transactions on Pattern Analysis and Machine Intelligence (PAMI) 2000 14 | * Normalized Cut Segmentation Code, Timothee Cour, Stella Yu, Jianbo Shi. Copyright 2004 University of Pennsylvania, Computer and Information Science Department. 15 | 16 | Tested on matlab R2009b. 17 | 18 | Installation Notes : 19 | 20 | 1) After you unzipped the files to mydir, 21 | put the Current Directory in Matlab to mydir 22 | 23 | 2) In the matlab command prompt, 24 | type compileDir_simple to compile the mex files (ignore the error on the C++ non-mex file; needs to be done once) 25 | 26 | 3) You can now try any of the functions 27 | 28 | type demoNcutImage to see a demo of image segmentation 29 | type demoNcutClustering to see a demo of point cloud clustering 30 | 31 | 32 | Other top level functions: 33 | 34 | NcutImage.m: given image "I", segment it into "nbSegments" segments 35 | [SegLabel,NcutDiscrete,NcutEigenvectors,NcutEigenvalues,W]= NcutImage(I,nbSegments); 36 | 37 | ICgraph.m: compute Intervening Contour based pixel similarity matrix W 38 | W = ICgraph(I); 39 | 40 | ncutW.m: Given a similarity graph "W", computes Ncut clustering on the graph into "nbSegments" groups; 41 | [NcutDiscrete,NcutEigenvectors,NcutEigenvalues] = ncutW(W,nbSegments); 42 | 43 | 44 | Release notes: 45 | 46 | 2010, January 22: release of all c++ source mex files compatible with matlab R2009b 47 | 2006, May 04: release version 8: fixed incompatibility issues with new matlab 48 | 2004, June 18: release version 7: initial release 49 | 50 | Maintained by Timothee Cour, timothee dot cour at gmail dot com 51 | 52 | January 22, 2010. -------------------------------------------------------------------------------- /Ncut/ncut.m: -------------------------------------------------------------------------------- 1 | function [Eigenvectors,Eigenvalues] = ncut(W,nbEigenValues,dataNcut); 2 | % function [Eigenvectors,Eigenvalues] = ncut(W,nbEigenValues,dataNcut); 3 | % 4 | % Input: 5 | % W= symmetric similarity matrix 6 | % nbEigenValues= number of Ncut eigenvectors computed 7 | % dataNcut= optional parameters 8 | % 9 | % default parameters for dataNcut: 10 | % dataNcut.offset = 5e-1; offset in the diagonal of W 11 | % dataNcut.verbose = 0; 0 for verbose off mode, 1,2,3 for verbose on modes 12 | % dataNcut.maxiterations = 100; max number of iterations in eigensolver 13 | % dataNcut.eigsErrorTolerance = 1e-6; error tolerance in eigensolver 14 | % dataNcut.valeurMin=1e-6; % truncates any values in W less than valeurMin 15 | % 16 | % Output: 17 | % Eigenvectors= continuouse Ncut eigenvectos, size = length(W) x nbEigenValues 18 | % Eigenvalues= Ncut eigenvalues, size = 1x nbEigenValues 19 | % 20 | % Timothee Cour, Stella Yu, Jianbo Shi, 2004. 21 | 22 | if nargin < 2 23 | nbEigenValues = 8; 24 | end 25 | if nargin < 3 26 | dataNcut.offset = 5e-1; 27 | dataNcut.verbose = 0; 28 | dataNcut.maxiterations = 300; 29 | dataNcut.eigsErrorTolerance = 1e-8; 30 | dataNcut.valeurMin=1e-6; 31 | end 32 | % if nargin < 3 33 | % dataNcut.offset = 5e-1; 34 | % dataNcut.verbose = 0; 35 | % dataNcut.maxiterations = 100; 36 | % dataNcut.eigsErrorTolerance = 1e-6; 37 | % dataNcut.valeurMin=1e-6; 38 | % end 39 | 40 | % make W matrix sparse 41 | W = sparsifyc(W,dataNcut.valeurMin); 42 | 43 | % check for matrix symmetry 44 | if max(max(abs(W-W'))) > 1e-10 %voir (-12) 45 | %disp(max(max(abs(W-W')))); 46 | error('W not symmetric'); 47 | end 48 | 49 | n = size(W,1); 50 | nbEigenValues = min(nbEigenValues,n); 51 | offset = dataNcut.offset; 52 | 53 | 54 | % degrees and regularization 55 | d = sum(abs(W),2); 56 | dr = 0.5 * (d - sum(W,2)); 57 | d = d + offset * 2; 58 | dr = dr + offset; 59 | W = W + spdiags(dr,0,n,n); 60 | 61 | Dinvsqrt = 1./sqrt(d+eps); 62 | P = spmtimesd(W,Dinvsqrt,Dinvsqrt); 63 | clear W; 64 | 65 | options.issym = 1; 66 | 67 | if dataNcut.verbose 68 | options.disp = 3; 69 | else 70 | options.disp = 0; 71 | end 72 | options.maxit = dataNcut.maxiterations; 73 | options.tol = dataNcut.eigsErrorTolerance; 74 | 75 | options.v0 = ones(size(P,1),1); 76 | options.p = max(35,2*nbEigenValues); %voir 77 | options.p = min(options.p,n); 78 | 79 | %warning off 80 | % [vbar,s,convergence] = eigs2(@mex_w_times_x_symmetric,size(P,1),nbEigenValues,'LA',options,tril(P)); 81 | [vbar,s,convergence] = eigs_new(@mex_w_times_x_symmetric,size(P,1),nbEigenValues,'LA',options,tril(P)); 82 | %warning on 83 | 84 | s = real(diag(s)); 85 | [x,y] = sort(-s); 86 | Eigenvalues = -x; 87 | vbar = vbar(:,y); 88 | Eigenvectors = spdiags(Dinvsqrt,0,n,n) * vbar; 89 | 90 | for i=1:size(Eigenvectors,2) 91 | Eigenvectors(:,i) = (Eigenvectors(:,i) / norm(Eigenvectors(:,i)) )*norm(ones(n,1)); 92 | if Eigenvectors(1,i)~=0 93 | Eigenvectors(:,i) = - Eigenvectors(:,i) * sign(Eigenvectors(1,i)); 94 | end 95 | end 96 | -------------------------------------------------------------------------------- /Ncut/ncut_2.m: -------------------------------------------------------------------------------- 1 | function [Eigenvectors,Eigenvalues] = ncut_2(W,nbEigenValues,dataNcut); 2 | % function [Eigenvectors,Eigenvalues] = ncut(W,nbEigenValues,dataNcut); 3 | % 4 | % Input: 5 | % W= symmetric similarity matrix 6 | % nbEigenValues= number of Ncut eigenvectors computed 7 | % dataNcut= optional parameters 8 | % 9 | % default parameters for dataNcut: 10 | % dataNcut.offset = 5e-1; offset in the diagonal of W 11 | % dataNcut.verbose = 0; 0 for verbose off mode, 1,2,3 for verbose on modes 12 | % dataNcut.maxiterations = 100; max number of iterations in eigensolver 13 | % dataNcut.eigsErrorTolerance = 1e-6; error tolerance in eigensolver 14 | % dataNcut.valeurMin=1e-6; % truncates any values in W less than valeurMin 15 | % 16 | % Output: 17 | % Eigenvectors= continuouse Ncut eigenvectos, size = length(W) x nbEigenValues 18 | % Eigenvalues= Ncut eigenvalues, size = 1x nbEigenValues 19 | % 20 | % Timothee Cour, Stella Yu, Jianbo Shi, 2004. 21 | 22 | if nargin < 2 23 | nbEigenValues = 8; 24 | end 25 | if nargin < 3 26 | dataNcut.offset = 5e-1; 27 | dataNcut.verbose = 0; 28 | dataNcut.maxiterations = 300; 29 | dataNcut.eigsErrorTolerance = 1e-8; 30 | dataNcut.valeurMin=1e-6; 31 | end 32 | % if nargin < 3 33 | % dataNcut.offset = 5e-1; 34 | % dataNcut.verbose = 0; 35 | % dataNcut.maxiterations = 100; 36 | % dataNcut.eigsErrorTolerance = 1e-6; 37 | % dataNcut.valeurMin=1e-6; 38 | % end 39 | 40 | % make W matrix sparse 41 | W = sparsifyc(W,dataNcut.valeurMin); 42 | 43 | % check for matrix symmetry 44 | if max(max(abs(W-W'))) > 1e-10 %voir (-12) 45 | %disp(max(max(abs(W-W')))); 46 | error('W not symmetric'); 47 | end 48 | 49 | n = size(W,1); 50 | nbEigenValues = min(nbEigenValues,n); 51 | offset = dataNcut.offset; 52 | 53 | 54 | % degrees and regularization 55 | d = sum(abs(W),2); 56 | dr = 0.5 * (d - sum(W,2)); 57 | d = d + offset * 2; 58 | dr = dr + offset; 59 | W = W + spdiags(dr,0,n,n); 60 | 61 | Dinvsqrt = 1./sqrt(d+eps); 62 | P = spmtimesd(W,Dinvsqrt,Dinvsqrt); 63 | clear W; 64 | 65 | options.issym = 1; 66 | 67 | if dataNcut.verbose 68 | options.disp = 3; 69 | else 70 | options.disp = 0; 71 | end 72 | options.maxit = dataNcut.maxiterations; 73 | options.tol = dataNcut.eigsErrorTolerance; 74 | 75 | options.v0 = ones(size(P,1),1); 76 | options.p = max(35,2*nbEigenValues); %voir 77 | options.p = min(options.p,n); 78 | 79 | %warning off 80 | % [vbar,s,convergence] = eigs2(@mex_w_times_x_symmetric,size(P,1),nbEigenValues,'LA',options,tril(P)); 81 | [vbar,s,convergence] = eigs(@mex_w_times_x_symmetric,size(P,1),nbEigenValues,'LA',options,tril(P)); 82 | %warning on 83 | 84 | s = real(diag(s)); 85 | [x,y] = sort(-s); 86 | Eigenvalues = -x; 87 | vbar = vbar(:,y); 88 | Eigenvectors = spdiags(Dinvsqrt,0,n,n) * vbar; 89 | 90 | for i=1:size(Eigenvectors,2) 91 | Eigenvectors(:,i) = (Eigenvectors(:,i) / norm(Eigenvectors(:,i)) )*norm(ones(n,1)); 92 | if Eigenvectors(1,i)~=0 93 | Eigenvectors(:,i) = - Eigenvectors(:,i) * sign(Eigenvectors(1,i)); 94 | end 95 | end 96 | -------------------------------------------------------------------------------- /Ncut/build_scene.m: -------------------------------------------------------------------------------- 1 | function [data,size_cluster] = build_scene(caseid) 2 | % [data,size_cluster] = build_scene(case) 3 | % 4 | % case 1: random gaussian shaped blobs. 5 | % case 2: one circular plus some gaussian blob, one inside, one outside 6 | % case 3: one circular plus some gaussian blob, one inside, two outside 7 | % Jianbo Shi, 1997 8 | 9 | 10 | if caseid ==1, 11 | sigma_h = 2; 12 | sigma_v = 10; 13 | 14 | s_v = 10; 15 | s_h = 30; 16 | 17 | a = [sigma_h*randn(1,40);sigma_v*randn(1,40)]; 18 | b = [s_h;s_v]*ones(1,50) + [sigma_h*randn(1,50);... 19 | sigma_v*randn(1,50)]; 20 | 21 | data = [a,b]; 22 | size_cluster = [40,50]; 23 | 24 | elseif caseid == 2, 25 | num_cluster = 3; 26 | radius = 15; 27 | size_cluster = [80,20,20]; 28 | 29 | raw_data = randn(2,sum(size_cluster)); 30 | tmp = rand(2,size_cluster(1))-0.5; 31 | 32 | [t,idt] = sort(tmp(2,:)); 33 | r_noise = 4; 34 | raw_data2 = [tmp(1,idt)*r_noise;... 35 | tmp(2,idt)*2]; 36 | 37 | data = [(radius-raw_data2(1,1:size_cluster(1))).*... 38 | cos(pi*raw_data2(2,1:size_cluster(1)));... 39 | (radius-raw_data2(1,1:size_cluster(1))).*... 40 | sin(pi*raw_data2(2,1:size_cluster(1)))]; 41 | 42 | 43 | center = [0,0];sig = [1,2]; 44 | % size_cluster_base 45 | scb = size_cluster(1)+1; 46 | scb_next = scb+size_cluster(2)-1; 47 | data = [data,[center(1)+sig(1)*raw_data(1,scb:scb_next);... 48 | center(2)+sig(2)*raw_data(2,scb:scb_next)]]; 49 | 50 | 51 | center = [radius+10,0]; sig = [1,1]; 52 | scb = scb_next+1; 53 | scb_next = scb+size_cluster(3)-1; 54 | data = [data,[center(1)+sig(1)*raw_data(1,scb:scb_next);... 55 | center(2)+sig(2)*raw_data(2,scb:scb_next)]]; 56 | elseif caseid==3, 57 | num_cluster = 4; 58 | radius = 15; 59 | size_cluster = [80,10,20,20]; 60 | 61 | raw_data = randn(2,sum(size_cluster)); 62 | tmp = rand(2,size_cluster(1))-0.5; 63 | 64 | [t,idt] = sort(tmp(2,:)); 65 | r_noise = 4; 66 | raw_data2 = [tmp(1,idt)*r_noise;... 67 | tmp(2,idt)*2]; 68 | 69 | data = [(radius-raw_data2(1,1:size_cluster(1))).*... 70 | cos(pi*raw_data2(2,1:size_cluster(1)));... 71 | (radius-raw_data2(1,1:size_cluster(1))).*... 72 | sin(pi*raw_data2(2,1:size_cluster(1)))]; 73 | 74 | 75 | center = [0,0];sig = [1,2]; 76 | % size_cluster_base 77 | scb = size_cluster(1)+1; 78 | scb_next = scb+size_cluster(2)-1; 79 | data = [data,[center(1)+sig(1)*raw_data(1,scb:scb_next);... 80 | center(2)+sig(2)*raw_data(2,scb:scb_next)]]; 81 | 82 | 83 | center = [radius+25,8]; sig = [1,2.3]; 84 | scb = scb_next+1; 85 | scb_next = scb+size_cluster(3)-1; 86 | data = [data,[center(1)+sig(1)*raw_data(1,scb:scb_next);... 87 | center(2)+sig(2)*raw_data(2,scb:scb_next)]]; 88 | 89 | center = [radius+25,-6]; sig = [1.5,2.4]; 90 | scb = scb_next+1; 91 | scb_next = scb+size_cluster(4)-1; 92 | data = [data,[center(1)+sig(1)*raw_data(1,scb:scb_next);... 93 | center(2)+sig(2)*raw_data(2,scb:scb_next)]]; 94 | elseif caseid == 4, 95 | size_cluster = [100,10,10]; 96 | radius = 10; 97 | tmp = rand(2,size_cluster(1))-0.5; 98 | 99 | [t,idt] = sort(tmp(2,:)); 100 | r_noise = 4; 101 | raw_data2 = [tmp(1,idt)*r_noise;... 102 | tmp(2,idt)*2]; 103 | 104 | data = [(radius-raw_data2(1,1:size_cluster(1))).*... 105 | cos(pi*raw_data2(2,1:size_cluster(1)));... 106 | (radius-raw_data2(1,1:size_cluster(1))).*... 107 | sin(pi*raw_data2(2,1:size_cluster(1)))]; 108 | 109 | 110 | result = zeros(1,size_cluster(1)); 111 | 112 | % for j =1:size_cluster(1), 113 | % result(j) = sum(sum(A(1:j,1:j)))/j; 114 | % end 115 | 116 | end 117 | -------------------------------------------------------------------------------- /Ncut/quadedgep.m: -------------------------------------------------------------------------------- 1 | % function [x,y,gx,gy,par,threshold,mag,mage,g,FIe,FIo,mago] = quadedgep(I,par,threshold); 2 | % Input: 3 | % I = image 4 | % par = vector for 4 parameters 5 | % [number of filter orientations, number of scales, filter size, elongation] 6 | % To use default values, put 0. 7 | % threshold = threshold on edge strength 8 | % Output: 9 | % [x,y,gx,gy] = locations and gradients of an ordered list of edgels 10 | % x,y could be horizontal or vertical or 45 between pixel sites 11 | % but it is guaranteed that there [floor(y) + (floor(x)-1)*nr] 12 | % is ordered and unique. In other words, each edgel has a unique pixel id. 13 | % par = actual par used 14 | % threshold = actual threshold used 15 | % mag = edge magnitude 16 | % mage = phase map 17 | % g = gradient map at each pixel 18 | % [FIe,FIo] = odd and even filter outputs 19 | % mago = odd filter output of optimum orientation 20 | % 21 | % Stella X. Yu, 2001 22 | 23 | 24 | 25 | function [x,y,gx,gy,par,threshold,mag,mage,g,FIe,FIo,mago] = quadedgep(I,par,threshold); 26 | 27 | if nargin<3 | isempty(threshold), 28 | threshold = 0.2; 29 | end 30 | 31 | [r,c] = size(I); 32 | def_par = [8,1,20,3]; 33 | 34 | % take care of parameters, any missing value is substituted by a default value 35 | if nargin<2 | isempty(par), 36 | par = def_par; 37 | end 38 | par(end+1:4)=0; 39 | par = par(:); 40 | j = (par>0); 41 | have_value = [ j, 1-j ]; 42 | j = 1; n_filter = have_value(j,:) * [par(j); def_par(j)]; 43 | j = 2; n_scale = have_value(j,:) * [par(j); def_par(j)]; 44 | j = 3; winsz = have_value(j,:) * [par(j); def_par(j)]; 45 | j = 4; enlong = have_value(j,:) * [par(j); def_par(j)]; 46 | 47 | % always make filter size an odd number so that the results will not be skewed 48 | j = winsz/2; 49 | if not(j > fix(j) + 0.1), 50 | winsz = winsz + 1; 51 | end 52 | 53 | % filter the image with quadrature filters 54 | FBo = make_filterbank_odd2(n_filter,n_scale,winsz,enlong); 55 | FBe = make_filterbank_even2(n_filter,n_scale,winsz,enlong); 56 | n = ceil(winsz/2); 57 | f = [fliplr(I(:,2:n+1)), I, fliplr(I(:,c-n:c-1))]; 58 | f = [flipud(f(2:n+1,:)); f; flipud(f(r-n:r-1,:))]; 59 | FIo = fft_filt_2(f,FBo,1); 60 | FIo = FIo(n+[1:r],n+[1:c],:); 61 | FIe = fft_filt_2(f,FBe,1); 62 | FIe = FIe(n+[1:r],n+[1:c],:); 63 | 64 | % compute the orientation energy and recover a smooth edge map 65 | % pick up the maximum energy across scale and orientation 66 | % even filter's output: as it is the second derivative, zero cross localize the edge 67 | % odd filter's output: orientation 68 | mag = sqrt(sum(FIo.^2,3)+sum(FIe.^2,3)); 69 | mag_a = sqrt(FIo.^2+FIe.^2); 70 | [tmp,max_id] = max(mag_a,[],3); 71 | base_size = r * c; 72 | id = [1:base_size]'; 73 | mage = reshape(FIe(id+(max_id(:)-1)*base_size),[r,c]); 74 | mage = (mage>0) - (mage<0); 75 | 76 | ori_incr=pi/n_filter; % to convert jshi's coords to conventional image xy 77 | ori_offset=ori_incr/2; 78 | theta = ori_offset+([1:n_filter]-1)*ori_incr; % orientation detectors 79 | % [gx,gy] are image gradient in image xy coords, winner take all 80 | mago = reshape(FIo(id+(max_id(:)-1)*base_size),[r,c]); 81 | ori = theta(max_id); 82 | ori = ori .* (mago>0) + (ori + pi).*(mago<0); 83 | gy = mag .* cos(ori); 84 | gx = -mag .* sin(ori); 85 | g = cat(3,gx,gy); 86 | 87 | % phase map: edges are where the phase changes 88 | mag_th = max(mag(:)) * threshold; 89 | eg = (mag>mag_th); 90 | h = eg & [(mage(2:r,:) ~= mage(1:r-1,:)); zeros(1,c)]; 91 | v = eg & [(mage(:,2:c) ~= mage(:,1:c-1)), zeros(r,1)]; 92 | [y,x] = find(h | v); 93 | k = y + (x-1) * r; 94 | h = h(k); 95 | v = v(k); 96 | y = y + h * 0.5; % i 97 | x = x + v * 0.5; % j 98 | t = h + v * r; 99 | gx = g(k) + g(k+t); 100 | k = k + (r * c); 101 | gy = g(k) + g(k+t); 102 | 103 | 104 | -------------------------------------------------------------------------------- /demo_1_ECPCS_MC.m: -------------------------------------------------------------------------------- 1 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2 | % This is a demo for ECPCS-MC, which is an ensemble clustering algorithm % 3 | % proposed in the following paper: % 4 | % % 5 | % D. Huang, C.-D. Wang, H. Peng, J. Lai, & C.-K. Kwoh. "Enhanced Ensemble % 6 | % Clustering via Fast Propagation of Cluster-wise Similarities."To appear % 7 | % in IEEE Transactions on Systems, Man, and Cybernetics: Systems. % 8 | % DOI: 10.1109/TSMC.2018.2876202 % 9 | % % 10 | % The code has been tested in Matlab R2016a and Matlab R2016b. % 11 | % % 12 | % www.researchgate.net/publication/328581758 % 13 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 14 | 15 | function demo_1_ECPCS_MC() 16 | %% Run the ECPCS-MC algorithm multiple times and show its average performance. 17 | 18 | clear all; 19 | close all; 20 | clc; 21 | 22 | %% Set up 23 | addpath('Ncut'); 24 | M = 20; % The number of base clusterings 25 | cntTimes = 10; % The number of times that the ECPCS-MC algorithm will be run. 26 | 27 | %% Load the data. 28 | dataName = 'BC'; 29 | % dataName = 'PD'; 30 | 31 | data = []; 32 | load(['data_',dataName,'.mat'],'data'); 33 | gt = data(:,1); 34 | fea = data(:,2:end); 35 | clear data 36 | 37 | [N, d] = size(fea); 38 | K = numel(unique(gt)); % The number of classes 39 | 40 | 41 | %% Ensemble clustering (by ECPCS-MC) 42 | nmiScores = zeros(cntTimes,1); 43 | disp('===================================================================='); 44 | disp(['Performing ensemble clustering on the ', dataName, ' dataset ',num2str(cntTimes),' times.']); 45 | disp(['N = ',num2str(N)]); 46 | disp('===================================================================='); 47 | for runIdx = 1:cntTimes 48 | disp('********************************************************************'); 49 | disp(['Run ', num2str(runIdx),':']); 50 | disp('********************************************************************'); 51 | 52 | %% Generating M base clusterings 53 | lowerK = K; 54 | upperK = min(100,floor(sqrt(N))); 55 | disp(['Generating ',num2str(M),' base clusterings...']); 56 | tic; 57 | % The non-paralleled version 58 | % baseCls = EnsembleGeneration(fea, M, lowerK, upperK); 59 | % The paralleled version 60 | baseCls = EnsembleGeneration_parallel(fea, M, lowerK, upperK); 61 | toc; 62 | 63 | %% Performing ECPCS-MC to obtain the consensus clustering. 64 | disp('Starting ECPCS-MC...'); 65 | tic; 66 | % You can use the default parameter t=20. 67 | Label = ECPCS_MC(baseCls, K); 68 | % Or you can set up parameter t by yourself. 69 | % t = 20; % The number of steps of the random walks 70 | % Label = ECPCS_MC(baseCls, K,t); 71 | disp('ECPCS-MC done.'); 72 | toc; 73 | 74 | disp('--------------------------------------------------------------------'); 75 | nmiScores(runIdx) = NMImax(Label,gt); 76 | disp(['The NMI score at Run ',num2str(runIdx), ': ',num2str(nmiScores(runIdx))]); 77 | disp('--------------------------------------------------------------------'); 78 | end 79 | 80 | disp('********************************************************************'); 81 | disp(['Average Performance (w.r.t. true-k) over ',num2str(cntTimes),' runs on the ',dataName,' dataset']); 82 | disp(['Sample size: N = ', num2str(N)]); 83 | disp(['Dimension: d = ', num2str(d)]); 84 | disp(['Ensemble size: M = ', num2str(M)]); 85 | disp('--------------------------------------------------------------------'); 86 | disp(['Average NMI score: ',num2str(mean(nmiScores))]); 87 | disp('--------------------------------------------------------------------'); 88 | disp('********************************************************************'); 89 | -------------------------------------------------------------------------------- /demo_2_ECPCS_HC.m: -------------------------------------------------------------------------------- 1 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2 | % This is a demo for ECPCS-HC, which is an ensemble clustering algorithm % 3 | % proposed in the following paper: % 4 | % % 5 | % D. Huang, C.-D. Wang, H. Peng, J. Lai, & C.-K. Kwoh. "Enhanced Ensemble % 6 | % Clustering via Fast Propagation of Cluster-wise Similarities."To appear % 7 | % in IEEE Transactions on Systems, Man, and Cybernetics: Systems. % 8 | % DOI: 10.1109/TSMC.2018.2876202 % 9 | % % 10 | % The code has been tested in Matlab R2016a and Matlab R2016b. % 11 | % % 12 | % www.researchgate.net/publication/328581758 % 13 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 14 | 15 | function demo_2_ECPCS_HC() 16 | %% Run the ECPCS-HC algorithm multiple times and show its average performance. 17 | 18 | clear all; 19 | close all; 20 | clc; 21 | 22 | %% Set up 23 | addpath('Ncut'); 24 | M = 20; % The number of base clusterings 25 | cntTimes = 10; % The number of times that the ECPCS-HC algorithm will be run. 26 | 27 | %% Load the data. 28 | dataName = 'BC'; 29 | % dataName = 'PD'; 30 | 31 | data = []; 32 | load(['data_',dataName,'.mat'],'data'); 33 | gt = data(:,1); 34 | fea = data(:,2:end); 35 | clear data 36 | 37 | [N, d] = size(fea); 38 | K = numel(unique(gt)); % The number of classes 39 | 40 | 41 | %% Ensemble clustering (by ECPCS-HC) 42 | nmiScores = zeros(cntTimes,1); 43 | disp('===================================================================='); 44 | disp(['Performing ensemble clustering on the ', dataName, ' dataset ',num2str(cntTimes),' times.']); 45 | disp(['N = ',num2str(N)]); 46 | disp('===================================================================='); 47 | for runIdx = 1:cntTimes 48 | disp('********************************************************************'); 49 | disp(['Run ', num2str(runIdx),':']); 50 | disp('********************************************************************'); 51 | 52 | %% Generating M base clusterings 53 | lowerK = K; 54 | upperK = min(100,floor(sqrt(N))); 55 | disp(['Generating ',num2str(M),' base clusterings...']); 56 | tic; 57 | % The non-paralleled version 58 | % baseCls = EnsembleGeneration(fea, M, lowerK, upperK); 59 | % The paralleled version 60 | baseCls = EnsembleGeneration_parallel(fea, M, lowerK, upperK); 61 | toc; 62 | 63 | %% Performing ECPCS-HC to obtain the consensus clustering. 64 | disp('Starting ECPCS-HC...'); 65 | tic; 66 | % You can use the default parameter t=20. 67 | Label = ECPCS_HC(baseCls, K); 68 | % Or you can set up parameter t by yourself. 69 | % t = 20; % The number of steps of the random walks 70 | % Label = ECPCS_HC(baseCls, K,t); 71 | disp('ECPCS-MC done.'); 72 | toc; 73 | disp('ECPCS-HC done.'); 74 | 75 | disp('--------------------------------------------------------------------'); 76 | nmiScores(runIdx) = NMImax(Label,gt); 77 | disp(['The NMI score at Run ',num2str(runIdx), ': ',num2str(nmiScores(runIdx))]); 78 | disp('--------------------------------------------------------------------'); 79 | end 80 | 81 | disp('********************************************************************'); 82 | disp(['Average Performance (w.r.t. true-k) over ',num2str(cntTimes),' runs on the ',dataName,' dataset']); 83 | disp(['Sample size: N = ', num2str(N)]); 84 | disp(['Dimension: d = ', num2str(d)]); 85 | disp(['Ensemble size: M = ', num2str(M)]); 86 | disp('--------------------------------------------------------------------'); 87 | disp(['Average NMI score: ',num2str(mean(nmiScores))]); 88 | disp('--------------------------------------------------------------------'); 89 | disp('********************************************************************'); 90 | -------------------------------------------------------------------------------- /Ncut/spmtimesd.cpp: -------------------------------------------------------------------------------- 1 | /*================================================================ 2 | * spmtimesd.c 3 | * This routine computes a sparse matrix times a diagonal matrix 4 | * whose diagonal entries are stored in a full vector. 5 | * 6 | * Examples: 7 | * spmtimesd(m,d,[]) = diag(d) * m, 8 | * spmtimesd(m,[],d) = m * diag(d) 9 | * spmtimesd(m,d1,d2) = diag(d1) * m * diag(d2) 10 | * m could be complex, but d is assumed real 11 | * 12 | * Stella X. Yu's first MEX function, Nov 9, 2001. 13 | 14 | % test sequence: 15 | 16 | m = 1000; 17 | n = 2000; 18 | a=sparse(rand(m,n)); 19 | d1 = rand(m,1); 20 | d2 = rand(n,1); 21 | tic; b=spmtimesd(a,d1,d2); toc 22 | tic; bb = spdiags(d1,0,m,m) * a * spdiags(d2,0,n,n); toc 23 | e = (bb-b); 24 | max(abs(e(:))) 25 | 26 | *=================================================================*/ 27 | 28 | # include "mex.h" 29 | 30 | void mexFunction( 31 | int nargout, 32 | mxArray *out[], 33 | int nargin, 34 | const mxArray *in[] 35 | ) 36 | { 37 | /* declare variables */ 38 | int i, j, k, m, n, nzmax, xm, yn; 39 | mwIndex *pir, *pjc, *qir, *qjc; 40 | double *x, *y, *pr, *pi, *qr, *qi; 41 | 42 | /* check argument */ 43 | if (nargin != 3) { 44 | mexErrMsgTxt("Three input arguments required"); 45 | } 46 | if (nargout>1) { 47 | mexErrMsgTxt("Too many output arguments."); 48 | } 49 | if (!(mxIsSparse(in[0]))) { 50 | mexErrMsgTxt("Input argument #1 must be of type sparse"); 51 | } 52 | if ( mxIsSparse(in[1]) || mxIsSparse(in[2]) ) { 53 | mexErrMsgTxt("Input argument #2 & #3 must be of type full"); 54 | } 55 | 56 | /* computation starts */ 57 | m = mxGetM(in[0]); 58 | n = mxGetN(in[0]); 59 | pr = mxGetPr(in[0]); 60 | pi = mxGetPi(in[0]); 61 | pir = mxGetIr(in[0]); 62 | pjc = mxGetJc(in[0]); 63 | 64 | i = mxGetM(in[1]); 65 | j = mxGetN(in[1]); 66 | xm = ((i>j)? i: j); 67 | 68 | i = mxGetM(in[2]); 69 | j = mxGetN(in[2]); 70 | yn = ((i>j)? i: j); 71 | 72 | if ( xm>0 && xm != m) { 73 | mexErrMsgTxt("Row multiplication dimension mismatch."); 74 | } 75 | if ( yn>0 && yn != n) { 76 | mexErrMsgTxt("Column multiplication dimension mismatch."); 77 | } 78 | 79 | 80 | nzmax = mxGetNzmax(in[0]); 81 | mxComplexity cmplx = (pi==NULL ? mxREAL : mxCOMPLEX); 82 | out[0] = mxCreateSparse(m,n,nzmax,cmplx); 83 | if (out[0]==NULL) { 84 | mexErrMsgTxt("Not enough space for the output matrix."); 85 | } 86 | 87 | qr = mxGetPr(out[0]); 88 | qi = mxGetPi(out[0]); 89 | qir = mxGetIr(out[0]); 90 | qjc = mxGetJc(out[0]); 91 | 92 | /* left multiplication */ 93 | x = mxGetPr(in[1]); 94 | if (yn==0) { 95 | for (j=0; j 35 | 36 | void mexFunction( 37 | int nargout, 38 | mxArray *out[], 39 | int nargin, 40 | const mxArray *in[] 41 | ) 42 | { 43 | /* declare variables */ 44 | int nr, nc, np, nb, total; 45 | double *dim, sample_rate; 46 | int r_i, r_j, a1, a2, b1, b2, self, neighbor; 47 | int i, j, k, s, t, nsamp, th_rand, no_sample; 48 | unsigned long *p; 49 | 50 | 51 | /* check argument */ 52 | if (nargin < 2) { 53 | mexErrMsgTxt("Two input arguments required"); 54 | } 55 | if (nargout> 2) { 56 | mexErrMsgTxt("Too many output arguments."); 57 | } 58 | 59 | /* get image size */ 60 | i = mxGetM(in[0]); 61 | j = mxGetN(in[0]); 62 | dim = (double *)mxGetData(in[0]); 63 | nr = (int)dim[0]; 64 | if (j>1 || i>1) { 65 | nc = (int)dim[1]; 66 | } else { 67 | nc = nr; 68 | } 69 | np = nr * nc; 70 | 71 | /* get neighbourhood size */ 72 | i = mxGetM(in[1]); 73 | j = mxGetN(in[1]); 74 | dim = (double*)mxGetData(in[1]); 75 | r_i = (int)dim[0]; 76 | if (j>1 || i>1) { 77 | r_j = (int)dim[1]; 78 | } else { 79 | r_j = r_i; 80 | } 81 | if (r_i<0) { r_i = 0; } 82 | if (r_j<0) { r_j = 0; } 83 | 84 | /* get sample rate */ 85 | if (nargin==3) { 86 | sample_rate = (mxGetM(in[2])==0) ? 1: mxGetScalar(in[2]); 87 | } else { 88 | sample_rate = 1; 89 | } 90 | /* prepare for random number generator */ 91 | if (sample_rate<1) { 92 | srand( (unsigned)time( NULL ) ); 93 | th_rand = (int)ceil((double)RAND_MAX * sample_rate); 94 | no_sample = 0; 95 | } else { 96 | sample_rate = 1; 97 | th_rand = RAND_MAX; 98 | no_sample = 1; 99 | } 100 | 101 | /* figure out neighbourhood size */ 102 | 103 | nb = (r_i + r_i + 1) * (r_j + r_j + 1); 104 | if (nb>np) { 105 | nb = np; 106 | } 107 | nb = (int)ceil((double)nb * sample_rate); 108 | 109 | /* intermediate data structure */ 110 | p = (unsigned long *)mxCalloc(np * (nb+1), sizeof(unsigned long)); 111 | if (p==NULL) { 112 | mexErrMsgTxt("Not enough space for my computation."); 113 | } 114 | 115 | /* computation */ 116 | total = 0; 117 | for (j=0; j=nc) { b2 = nc-1; } 130 | 131 | /* i range */ 132 | a1 = i - r_i; 133 | if (a1<0) { a1 = 0; } 134 | a2 = i + r_i; 135 | if (a2>=nr) { a2 = nr-1; } 136 | 137 | /* number of more samples needed */ 138 | nsamp = nb - p[self]; 139 | 140 | k = 0; 141 | t = b1; 142 | s = i + 1; 143 | if (s>a2) { 144 | s = a1; 145 | t = t + 1; 146 | } 147 | while (ka2) { 160 | s = a1; 161 | t = t + 1; 162 | } 163 | } /* k */ 164 | 165 | total = total + p[self]; 166 | } /* i */ 167 | } /* j */ 168 | 169 | /* i, j */ 170 | out[0] = mxCreateNumericMatrix(total, 1, mxUINT32_CLASS, mxREAL); 171 | out[1] = mxCreateNumericMatrix(np+1, 1, mxUINT32_CLASS, mxREAL); 172 | unsigned int *qi = (unsigned int *)mxGetData(out[0]); 173 | unsigned int *qj = (unsigned int *)mxGetData(out[1]); 174 | if (out[0]==NULL || out[1]==NULL) { 175 | mexErrMsgTxt("Not enough space for the output matrix."); 176 | } 177 | 178 | total = 0; 179 | for (j=0; j1) { 46 | mexErrMsgTxt("Too many output arguments"); 47 | } 48 | 49 | /* get edgel information */ 50 | nr = mxGetM(in[0]); 51 | nc = mxGetN(in[0]); 52 | if ( nr*nc ==0 || nr != mxGetM(in[1]) || nc != mxGetN(in[1]) ) { 53 | mexErrMsgTxt("Edge magnitude and phase shall be of the same image size"); 54 | } 55 | emag = mxGetPr(in[0]); 56 | ephase = mxGetPr(in[1]); 57 | np = nr * nc; 58 | 59 | /* get new index pair */ 60 | if (!mxIsUint32(in[2]) | !mxIsUint32(in[3])) { 61 | mexErrMsgTxt("Index pair shall be of type UINT32"); 62 | } 63 | if (mxGetM(in[3]) * mxGetN(in[3]) != np + 1) { 64 | mexErrMsgTxt("Wrong index representation"); 65 | } 66 | pi = (unsigned int*)mxGetData(in[2]); 67 | pj = (unsigned int*)mxGetData(in[3]); 68 | 69 | /* create output */ 70 | out[0] = mxCreateSparse(np,np,pj[np],mxREAL); 71 | if (out[0]==NULL) { 72 | mexErrMsgTxt("Not enough memory for the output matrix"); 73 | } 74 | w = mxGetPr(out[0]); 75 | ir = mxGetIr(out[0]); 76 | jc = mxGetJc(out[0]); 77 | 78 | /* find my sigma */ 79 | if (nargin<5) { 80 | sigma = 0; 81 | for (k=0; ksigma) { sigma = emag[k]; } 83 | } 84 | sigma = sigma / 6; 85 | printf("sigma = %6.5f",sigma); 86 | } else { 87 | sigma = mxGetScalar(in[4]); 88 | } 89 | a = 0.5 / (sigma * sigma); 90 | 91 | /* computation */ 92 | total = 0; 93 | for (j=0; j= abs(dj)) { 121 | slope = dj / di; 122 | step = (iy>=jy) ? 1 : -1; 123 | 124 | iip1 = jy; 125 | jjp1 = jx; 126 | 127 | 128 | for (ii=0;ii maxori){ 137 | maxori = z; 138 | } 139 | } 140 | 141 | iip1 = iip2; 142 | jjp1 = jjp2; 143 | phase1 = phase2; 144 | } 145 | 146 | /* sample in j direction */ 147 | } else { 148 | slope = di / dj; 149 | step = (ix>=jx) ? 1: -1; 150 | 151 | jjp1 = jx; 152 | iip1 = jy; 153 | 154 | 155 | for (jj=0;jj maxori){ 164 | maxori = z; 165 | } 166 | 167 | } 168 | 169 | iip1 = iip2; 170 | jjp1 = jjp2; 171 | phase1 = phase2; 172 | } 173 | } 174 | 175 | maxori = 0.5 * maxori; 176 | maxori = exp(-maxori * maxori * a); 177 | } 178 | ir[total] = i; 179 | 180 | w[total] = maxori; 181 | total = total + 1; 182 | 183 | } /* i */ 184 | } /* j */ 185 | 186 | jc[np] = total; 187 | } 188 | -------------------------------------------------------------------------------- /Ncut/sparsifyc.cpp: -------------------------------------------------------------------------------- 1 | /*================================================================= 2 | * syntax: SPMX = SPARSIFY(MX, THRES) 3 | * 4 | * SPARSIFY - sparsify the input matrix, i.e. ignore the values 5 | * of the matrix which are below a threshold 6 | * 7 | * Input: - MX: m-by-n matrix (sparse or full) 8 | * - THRES: threshold value (double) 9 | * 10 | * Output: - SPMX: m-by-n sparse matrix only with values 11 | * whose absolut value is above the given threshold 12 | * 13 | * Written by Mirko Visontai (10/24/2003) 14 | *=================================================================*/ 15 | 16 | 17 | #include 18 | #include "mex.h" 19 | 20 | void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) 21 | { 22 | /* Declare variable */ 23 | int i,m,n,nzmax,newnnz,col,processed,passed; 24 | int starting_row_index, current_row_index, stopping_row_index; 25 | double *in_pr,*in_pi,*out_pr,*out_pi; 26 | mwIndex *in_ir,*in_jc,*out_ir,*out_jc; 27 | double thres; 28 | 29 | /* Check for proper number of input and output arguments */ 30 | if ((nlhs != 1) || (nrhs != 2)){ 31 | mexErrMsgTxt("usage: SPMX = SPARSIFY(MX, THRES)."); 32 | } 33 | /* if matrix is complex threshold the norm of the numbers */ 34 | if (mxIsComplex(prhs[0])){ 35 | /* Check data type of input argument */ 36 | if (mxIsSparse(prhs[0])){ 37 | 38 | /* read input */ 39 | in_pr = mxGetPr(prhs[0]); 40 | in_pi = mxGetPi(prhs[0]); 41 | in_ir = mxGetIr(prhs[0]); 42 | in_jc = mxGetJc(prhs[0]); 43 | nzmax = mxGetNzmax(prhs[0]); 44 | m = mxGetM(prhs[0]); 45 | n = mxGetN(prhs[0]); 46 | thres = mxGetScalar(prhs[1]); 47 | 48 | /* Count new nonzeros */ 49 | newnnz=0; 50 | for(i=0; ithres) {newnnz++;} 52 | } 53 | 54 | if (newnnz>0){ 55 | /* create output */ 56 | plhs[0] = mxCreateSparse(m,n,newnnz,mxCOMPLEX); 57 | if (plhs[0]==NULL) 58 | mexErrMsgTxt("Could not allocate enough memory!\n"); 59 | out_pr = mxGetPr(plhs[0]); 60 | out_pi = mxGetPr(plhs[0]); 61 | out_ir = mxGetIr(plhs[0]); 62 | out_jc = mxGetJc(plhs[0]); 63 | passed = 0; 64 | out_jc[0] = 0; 65 | for (col=0; col thres){ 77 | 78 | out_pr[passed]=in_pr[current_row_index]; 79 | out_pi[passed]=in_pi[current_row_index]; 80 | out_ir[passed]=in_ir[current_row_index]; 81 | out_jc[col+1] = out_jc[col+1]+1; 82 | passed++; 83 | } 84 | } 85 | } 86 | } 87 | } 88 | else{ 89 | plhs[0] = mxCreateSparse(m,n,0,mxCOMPLEX); 90 | } 91 | } 92 | else{ /* for full matrices */ 93 | /* read input */ 94 | in_pr = mxGetPr(prhs[0]); 95 | in_pi = mxGetPr(prhs[0]); 96 | m = mxGetM(prhs[0]); 97 | n = mxGetN(prhs[0]); 98 | thres = mxGetScalar(prhs[1]); 99 | 100 | /* Count new nonzeros */ 101 | newnnz=0; 102 | for(i=0; ithres) {newnnz++;} 104 | } 105 | 106 | if (newnnz>0){ 107 | /* create output */ 108 | plhs[0] = mxCreateSparse(m,n,newnnz,mxCOMPLEX); 109 | if (plhs[0]==NULL) 110 | mexErrMsgTxt("Could not allocate enough memory!\n"); 111 | out_pr = mxGetPr(plhs[0]); 112 | out_pi = mxGetPi(plhs[0]); 113 | out_ir = mxGetIr(plhs[0]); 114 | out_jc = mxGetJc(plhs[0]); 115 | passed = 0; 116 | out_jc[0] = 0; 117 | 118 | for (col=0; col thres){ 123 | 124 | out_pr[passed]=in_pr[current_row_index+m*col]; 125 | out_ir[passed]=current_row_index; 126 | out_jc[col+1] = out_jc[col+1]+1; 127 | passed++; 128 | } 129 | } 130 | } 131 | } 132 | else{ 133 | plhs[0] = mxCreateSparse(m,n,0,mxCOMPLEX); 134 | } 135 | } 136 | } 137 | else { 138 | /* Check data type of input argument */ 139 | if (mxIsSparse(prhs[0])){ 140 | 141 | /* read input */ 142 | in_pr = mxGetPr(prhs[0]); 143 | in_ir = mxGetIr(prhs[0]); 144 | in_jc = mxGetJc(prhs[0]); 145 | nzmax = mxGetNzmax(prhs[0]); 146 | n = mxGetN(prhs[0]); 147 | m = mxGetM(prhs[0]); 148 | thres = mxGetScalar(prhs[1]); 149 | 150 | /* Count new nonzeros */ 151 | newnnz=0; 152 | for(i=0; ithres) {newnnz++;} 154 | } 155 | 156 | if (newnnz>0){ 157 | /* create output */ 158 | plhs[0] = mxCreateSparse(m,n,newnnz,mxREAL); 159 | if (plhs[0]==NULL) 160 | mexErrMsgTxt("Could not allocate enough memory!\n"); 161 | out_pr = mxGetPr(plhs[0]); 162 | out_ir = mxGetIr(plhs[0]); 163 | out_jc = mxGetJc(plhs[0]); 164 | passed = 0; 165 | out_jc[0] = 0; 166 | for (col=0; colthres){ 177 | out_pr[passed]=in_pr[current_row_index]; 178 | out_ir[passed]=in_ir[current_row_index]; 179 | out_jc[col+1] = out_jc[col+1]+1; 180 | passed++; 181 | } 182 | } 183 | } 184 | } 185 | } 186 | else{ 187 | plhs[0] = mxCreateSparse(m,n,0,mxREAL); 188 | } 189 | } 190 | else{ /* for full matrices */ 191 | /* read input */ 192 | in_pr = mxGetPr(prhs[0]); 193 | n = mxGetN(prhs[0]); 194 | m = mxGetM(prhs[0]); 195 | thres = mxGetScalar(prhs[1]); 196 | 197 | /* Count new nonzeros */ 198 | newnnz=0; 199 | for(i=0; ithres) {newnnz++;} 201 | } 202 | 203 | if (newnnz>0){ 204 | /* create output */ 205 | plhs[0] = mxCreateSparse(m,n,newnnz,mxREAL); 206 | if (plhs[0]==NULL) 207 | mexErrMsgTxt("Could not allocate enough memory!\n"); 208 | out_pr = mxGetPr(plhs[0]); 209 | out_ir = mxGetIr(plhs[0]); 210 | out_jc = mxGetJc(plhs[0]); 211 | passed = 0; 212 | out_jc[0] = 0; 213 | 214 | for (col=0; colthres){ 218 | out_pr[passed]=in_pr[current_row_index+m*col]; 219 | out_ir[passed]=current_row_index; 220 | out_jc[col+1] = out_jc[col+1]+1; 221 | passed++; 222 | } 223 | } 224 | } 225 | } 226 | else{ 227 | plhs[0] = mxCreateSparse(m,n,0,mxREAL); 228 | } 229 | } 230 | } 231 | } 232 | 233 | -------------------------------------------------------------------------------- /Ncut/a_times_b_cmplx.cpp: -------------------------------------------------------------------------------- 1 | /*================================================================ 2 | a_times_b_cmplx.c = used by a couple of mex functions 3 | provide Matrix vector multiplications, 4 | and solve triangular systems 5 | (sparse matrix and full vector) 6 | 7 | CSC_CmplxVecMult_CAB_double, CSR_CmplxVecMult_CAB_double, 8 | CSCsymm_CmplxVecMult_CAB_double added by Mirko Visontai (10/24/2003) 9 | 10 | *=================================================================*/ 11 | # include "math.h" 12 | 13 | ///*c<-a'*b */ 14 | //void scalar_product( 15 | // const int m, const int k, /*nb_rows, nb_columns*/ 16 | // const double *a, 17 | // const double *b, 18 | // double *c 19 | // ) 20 | //{ 21 | // int i; 22 | // double d; 23 | // d = 0; 24 | // for (i=0;i!=m;i++) 25 | // d+=a[i]*b[i]; 26 | // c[0] = d; 27 | // 28 | //} 29 | 30 | 31 | /*C<-a*A*B+C*/ 32 | void CSC_VecMult_CaABC_double( 33 | const int m, const int k, const double alpha, 34 | const double *val, const int *indx, 35 | const int *pntrb, 36 | const double *b, 37 | double *c) 38 | { 39 | int i,j,jb,je; 40 | 41 | for (i=0;i!=k;i++){ 42 | jb = pntrb[i]; 43 | je = pntrb[i+1]; 44 | for (j=jb;j!=je;j++) 45 | c[indx[j]] += alpha * b[i] * val[j]; 46 | } 47 | } 48 | 49 | /*C<-a*A'*B+C*/ 50 | void CSR_VecMult_CaABC_double( 51 | const int k, const int m, const double alpha, 52 | const double *val, const mwIndex *indx, 53 | const mwIndex *pntrb, 54 | const double *b, 55 | double *c) 56 | { 57 | double t; 58 | const double *pval; 59 | int i,j,jb,je; 60 | 61 | pval = val; 62 | for (i=0;i!=m;i++) { 63 | t = 0; 64 | jb = pntrb[i]; 65 | je = pntrb[i+1]; 66 | for (j=jb;j!=je;j++) 67 | t += alpha * b[indx[j]] * (*pval++); 68 | c[i] += t; 69 | } 70 | } 71 | 72 | 73 | /*C<-A*b */ 74 | void CSC_VecMult_CAB_double( 75 | const int m, const int k, /*nb_rows, nb_columns*/ 76 | const double *val, const int *indx, 77 | const int *pntrb, 78 | const double *b, 79 | double *c 80 | ) 81 | { 82 | int i,j,jb,je; 83 | double *pc=c; 84 | for (i=0;i!=m;i++) *pc++ = 0; 85 | 86 | for (i=0;i!=k;i++){ 87 | jb = pntrb[i]; 88 | je = pntrb[i+1]; 89 | for (j=jb;j!=je;j++) 90 | c[indx[j]] += b[i] * val[j]; 91 | } 92 | } 93 | 94 | /*C<-A*b (complex)*/ 95 | void CSC_CmplxVecMult_CAB_double( 96 | const int m, const int k, 97 | const double *valr, const double *vali, 98 | const int *indx, 99 | const int *pntrb, 100 | const double *br, const double *bi, 101 | double *cr, double *ci 102 | ) 103 | { 104 | int i,j,jb,je; 105 | double *pcr=cr; 106 | double *pci=ci; 107 | for (i=0;i!=m;i++){ 108 | *pcr++ = 0.0; 109 | *pci++ = 0.0; 110 | } 111 | 112 | for (i=0;i!=k;i++){ 113 | jb = pntrb[i]; 114 | je = pntrb[i+1]; 115 | for (j=jb;j!=je;j++){ 116 | cr[indx[j]] += (br[i] * valr[j]) - (bi[i] * vali[j]); 117 | ci[indx[j]] += (br[i] * vali[j]) + (bi[i] * valr[j]); 118 | } 119 | } 120 | } 121 | 122 | /*C<-A'*b 123 | plus rapide que CSC_VecMult_CAB_double */ 124 | void CSR_VecMult_CAB_double( 125 | const int k, const int m, 126 | const double *val, const int *indx, 127 | const int *pntrb, 128 | const double *b, 129 | double *c 130 | ) 131 | { 132 | double t; 133 | const double *pval; 134 | double *pc=c; 135 | int i,j,jb,je; 136 | 137 | for (i=0;i!=m;i++) *pc++ = 0; 138 | 139 | pval = val; 140 | for (i=0;i!=m;i++) { 141 | t = 0; 142 | jb = pntrb[i]; 143 | je = pntrb[i+1]; 144 | for (j=jb;j!=je;j++) 145 | t += b[indx[j]] * (*pval++); 146 | c[i] += t; 147 | } 148 | } 149 | 150 | /*C<-A'*b (complex) 151 | plus rapide que CSC_VecMult_CAB_double */ 152 | void CSR_CmplxVecMult_CAB_double( 153 | const int k, const int m, 154 | const double *valr, const double *vali, 155 | const int *indx, 156 | const int *pntrb, 157 | const double *br, const double *bi, 158 | double *cr, double *ci 159 | ) 160 | { 161 | double tr, ti; 162 | const double *pvalr; 163 | const double *pvali; 164 | double *pcr=cr; 165 | double *pci=ci; 166 | int i,j,jb,je; 167 | 168 | for (i=0;i!=m;i++){ 169 | *pcr++ = 0.0; 170 | *pci++ = 0.0; 171 | } 172 | 173 | pvalr = valr; 174 | pvali = vali; 175 | for (i=0;i!=m;i++) { 176 | tr = 0.0; 177 | ti = 0.0; 178 | jb = pntrb[i]; 179 | je = pntrb[i+1]; 180 | for (j=jb;j!=je;j++){ 181 | tr += (br[indx[j]] * (*pvalr)) - (bi[indx[j]] * (*pvali)); 182 | ti += (br[indx[j]] * (*pvali++)) + (bi[indx[j]] * (*pvalr++)); 183 | } 184 | cr[i] += tr; 185 | ci[i] += ti; 186 | } 187 | } 188 | 189 | 190 | 191 | /* C<-A*b (A is symmetric) */ 192 | void CSRsymm_VecMult_CAB_double( 193 | const int k, const int m, 194 | const double *val, const mwIndex *indx, 195 | const mwIndex *pntrb, 196 | const double *b, 197 | double *c 198 | ) 199 | { 200 | const double *pval; 201 | double *pc=c; 202 | int i,j; 203 | int jj; 204 | int rpntrb, rpntre; 205 | int index, nvals; 206 | 207 | 208 | for (i=0;i!=m;i++) *pc++ = 0; 209 | pval = val; 210 | for (j=0;j!=k;j++){ 211 | rpntrb = pntrb[j]; 212 | rpntre = pntrb[j+1]; 213 | for (jj=rpntrb;jj!=rpntre;jj++) { 214 | index = indx[jj]; 215 | if ( index == j ) { 216 | c[j] += b[j] * (*pval++); 217 | continue; 218 | } 219 | if ( index > j ) { 220 | c[index] += b[j] * (*pval); 221 | 222 | c[j] += b[index] * (*pval++); 223 | } 224 | else { 225 | pval++; 226 | } 227 | } 228 | } 229 | } 230 | 231 | 232 | /* C<-A*b (A is symmetric and complex) */ 233 | void CSRsymm_CmplxVecMult_CAB_double( 234 | const int k, const int m, 235 | const double *valr, const double *vali, 236 | const int *indx, 237 | const int *pntrb, 238 | const double *br, const double *bi, 239 | double *cr, double *ci 240 | ) 241 | { 242 | const double *pvalr, *pvali; 243 | double *pcr=cr; 244 | double *pci=ci; 245 | int i,j; 246 | int jj; 247 | int rpntrb, rpntre; 248 | int index, nvals; 249 | 250 | 251 | for (i=0;i!=m;i++){ 252 | *pcr++ = 0.0; 253 | *pci++ = 0.0; 254 | } 255 | 256 | pvalr = valr; 257 | pvali = vali; 258 | for (j=0;j!=k;j++){ 259 | rpntrb = pntrb[j]; 260 | rpntre = pntrb[j+1]; 261 | for (jj=rpntrb;jj!=rpntre;jj++) { 262 | index = indx[jj]; 263 | if ( index == j ) { 264 | cr[j] += (br[j] * (*pvalr)) - (bi[j] * (*pvali)); 265 | ci[j] += (br[j] * (*pvali++)) + (bi[j] * (*pvalr++)); 266 | continue; 267 | } 268 | if ( index > j ) { 269 | cr[index] += (br[j] * (*pvalr)) - (bi[j] * (*pvali)); 270 | ci[index] += (br[j] * (*pvali)) + (bi[j] * (*pvalr)); 271 | 272 | cr[j] += (br[index] * (*pvalr)) - (bi[index] * (*pvali)); 273 | ci[j] += (br[index] * (*pvali++)) + (bi[index] * (*pvalr++)); 274 | } 275 | else { 276 | pvalr++; 277 | pvali++; 278 | } 279 | 280 | } 281 | } 282 | } 283 | 284 | 285 | /*C<-A\B; with Lower triangular A*/ 286 | void CSC_VecTriangSlvLD_CAB_double( 287 | const int m, 288 | const double *val, 289 | const int *indx, const int *pntrb, 290 | const double *b, 291 | double *c) 292 | { 293 | int i, j, jb, je; 294 | double *pc=c; 295 | double z; 296 | 297 | for (i=0;i!=m;i++){ 298 | *pc = b[i]; 299 | pc++; 300 | } 301 | 302 | pc=c; 303 | for (i=0;i!=m;i++) { 304 | jb = pntrb[i]; 305 | je = pntrb[i+1]; 306 | z = pc[i] / val[jb]; 307 | pc[i] = z; 308 | for (j=jb+1;j 3) 83 | error('MATLAB:eigs:TooManyOutputs', 'Too many output arguments.') 84 | end 85 | 86 | % Platform dependent integer type 87 | if strfind(computer, '64') 88 | intconvert = @(arraytoconvert) int64(arraytoconvert); 89 | inttype = 'int64'; 90 | else 91 | intconvert = @(arraytoconvert) int32(arraytoconvert); 92 | inttype = 'int32'; 93 | end 94 | 95 | % Error check inputs and derive some information from them 96 | [A,Amatrix,isrealprob,issymA,n,B,classAB,k,eigs_sigma,whch, ... 97 | sigma,tol,maxit,p,info,eigs_display,cholB,permB,resid,useeig, ... 98 | afunNargs,style,mode,Afactors,Bfactors] = ... 99 | checkInputs(varargin{:}); 100 | 101 | % Now have enough information to do early return on cases EIGS does not 102 | % handle. For these cases, use the full EIG code. 103 | if useeig 104 | fullEig(nargout); 105 | return 106 | end 107 | 108 | if ~isempty(Afactors) 109 | L = Afactors.L; Afactors.L = []; 110 | U = Afactors.U; Afactors.U = []; 111 | pp = Afactors.pp; Afactors.pp = []; 112 | qq = Afactors.qq; Afactors.qq = []; 113 | dgAsB = Afactors.dgAsB; Afactors.dgAsB = []; 114 | clear Afactors; 115 | end 116 | 117 | if ~isempty(Bfactors) 118 | BisHpd = Bfactors.BisHpd; 119 | if BisHpd 120 | RB = Bfactors.RB; Bfactors.RB = []; 121 | RBT = Bfactors.RBT; Bfactors.RBT = []; 122 | permB = Bfactors.permB; Bfactors.permB = []; 123 | else 124 | LB = Bfactors.LB; Bfactors.LB = []; 125 | UB = Bfactors.UB; Bfactors.UB = []; 126 | ppB = Bfactors.ppB; Bfactors.ppB = []; 127 | qqB = Bfactors.qqB; Bfactors.qqB = []; 128 | dgB = Bfactors.dgB; Bfactors.dgB = []; 129 | end 130 | clear Bfactors; 131 | end 132 | 133 | if isempty(B) 134 | if mode ~= 3 135 | % OP = A 136 | applyOP = @(v)Amtimes(v); 137 | else 138 | % OP = (A-\sigma*I)^{-1} 139 | applyOP = @(v)AminusSigmaBsolve(v); 140 | end 141 | else 142 | if mode ~= 3 && BisHpd == true 143 | % OP = L^{-1}AL^{-T} (B = LL^T) 144 | applyOP = @(v)RBTsolve(Amtimes(RBsolve(v))); 145 | elseif mode ~= 3 && BisHpd == false 146 | % OP = U^{-1}L^{-1}A (B = LU) 147 | applyOP = @(v)Bsolve(Amtimes(v)); 148 | else 149 | % OP = (A-\sigma*B)^{-1}B 150 | applyOP = @(v)AminusSigmaBsolve(Bmtimes(v)); 151 | end 152 | end 153 | if strcmp(style,'G') 154 | if ~isempty(B) && BisHpd == true && mode == 3 155 | applyM = @(v) Bmtimes(v); 156 | else 157 | applyM = @(v) v; 158 | end 159 | end 160 | 161 | % Allocate outputs and ARPACK work variables 162 | if isrealprob 163 | if issymA % real and symmetric 164 | if strcmp(classAB,'single') 165 | aupdfun = 'ssaupd'; 166 | eupdfun = 'sseupd'; 167 | else 168 | aupdfun = 'dsaupd'; 169 | eupdfun = 'dseupd'; 170 | end 171 | lworkl = intconvert(p*(p+8)); 172 | d = zeros(k,1,classAB); 173 | else % real but not symmetric 174 | if strcmp(classAB,'single') 175 | aupdfun = 'snaupd'; 176 | eupdfun = 'sneupd'; 177 | else 178 | aupdfun = 'dnaupd'; 179 | eupdfun = 'dneupd'; 180 | end 181 | lworkl = intconvert(3*p*(p+2)); 182 | workev = zeros(3*p,1,classAB); 183 | d = zeros(k+1,1,classAB); 184 | di = zeros(k+1,1,classAB); 185 | end 186 | v = zeros(n,p,classAB); 187 | workd = zeros(n,3,classAB); 188 | workl = zeros(lworkl,1,classAB); 189 | else % complex 190 | if strcmp(classAB,'single') 191 | aupdfun = 'cnaupd'; 192 | eupdfun = 'cneupd'; 193 | else 194 | aupdfun = 'znaupd'; 195 | eupdfun = 'zneupd'; 196 | end 197 | zv = zeros(2*n*p,1,classAB); 198 | workd = complex(zeros(n,3,classAB)); 199 | zworkd = zeros(2*numel(workd),1,classAB); 200 | lworkl = intconvert(2*(3*p^2+5*p)); 201 | workl = zeros(lworkl,1,classAB); 202 | workev = zeros(2*2*p,1,classAB); 203 | zd = zeros(2*(k+1),1,classAB); 204 | rwork = zeros(p,1,classAB); 205 | end 206 | ldv = intconvert(n); 207 | ipntr = zeros(15,1,inttype); 208 | ido = intconvert(0); % reverse communication parameter, initial value 209 | if strcmp(style,'S') 210 | bmat = 'I'; % standard eigenvalue problem 211 | else 212 | bmat = 'G'; % generalized eigenvalue problem 213 | end 214 | nev = intconvert(k); % number of eigenvalues requested 215 | ncv = intconvert(p); % number of Lanczos vectors 216 | iparam = zeros(11,1,inttype); 217 | % iparam(1) = ishift = 1 ensures we are never asked to handle ido=3 218 | iparam([1 3 7]) = [1 maxit mode]; 219 | select = zeros(p,1,inttype); 220 | 221 | % To Do: Remove this error when ARPACKC supports singles 222 | if strcmp(classAB,'single') 223 | error('MATLAB:eigs:single', ... 224 | 'EIGS does not support single precision inputs.') 225 | end 226 | 227 | % The ARPACK routines return to EIGS many times per each iteration but we 228 | % only want to display the Ritz values once per iteration (if opts.disp>0). 229 | % Keep track of whether we've displayed this iteration yet in eigs_iter. 230 | eigs_iter = 0; 231 | 232 | cputms(1) = cputime - t0; % end timing pre-processing 233 | 234 | % Iterate until ARPACK's reverse communication parameter ido says to stop 235 | while (ido ~= 99) 236 | 237 | t0 = cputime; % start timing ARPACK calls **aupd 238 | 239 | if isrealprob 240 | arpackc( aupdfun, ido, ... 241 | bmat, intconvert(n), whch, nev, tol, resid, ncv, ... 242 | v, ldv, iparam, ipntr, workd, workl, lworkl, info ); 243 | else 244 | % The FORTRAN ARPACK routine expects the complex input zworkd to have 245 | % real and imaginary parts interleaved, but the OP about to be 246 | % applied to workd expects it in MATLAB's complex representation with 247 | % separate real and imaginary parts. Thus we need both. 248 | zworkd(1:2:end-1) = real(workd); 249 | zworkd(2:2:end) = imag(workd); 250 | arpackc( aupdfun, ido, ... 251 | bmat, intconvert(n), whch, nev, tol, resid, ncv, ... 252 | zv, ldv, iparam, ipntr, zworkd, workl, lworkl, rwork, info ); 253 | workd = reshape(complex(zworkd(1:2:end-1),zworkd(2:2:end)),[n,3]); 254 | end 255 | 256 | if (info < 0) 257 | error('MATLAB:eigs:ARPACKroutineError', ... 258 | 'Error with ARPACK routine %s: info = %d', ... 259 | aupdfun,full(double(info))) 260 | end 261 | 262 | cputms(2) = cputms(2) + (cputime-t0); % end timing ARPACK calls **aupd 263 | t0 = cputime; % start timing MATLAB OP(X) 264 | 265 | % Compute which columns of workd ipntr references 266 | cols = checkIpntr; 267 | 268 | % The ARPACK reverse communication parameter ido tells EIGS what to do 269 | 270 | switch ido 271 | case -1 272 | workd(:,cols(2)) = applyOP(workd(:,cols(1))); 273 | if strcmp(style,'G') && mode ~= 3 274 | workd(:,cols(1)) = workd(:,cols(2)); 275 | end 276 | case 1 277 | if strcmp(style,'G') && mode == 3 && (isempty(B) || BisHpd) 278 | % use with B-inner product for mode 3; see applyM 279 | workd(:,cols(2)) = AminusSigmaBsolve(workd(:,cols(3))); 280 | else 281 | % same work as case -1 282 | workd(:,cols(2)) = applyOP(workd(:,cols(1))); 283 | if strcmp(style,'G') && mode ~= 3 284 | % use with std inner product; see applyM 285 | workd(:,cols(1)) = workd(:,cols(2)); 286 | end 287 | end 288 | case 2 289 | workd(:,cols(2)) = applyM(workd(:,cols(1))); 290 | case 99 291 | % ARPACK has converged 292 | otherwise 293 | error('MATLAB:eigs:UnknownIdo','Unknown ido.'); 294 | end 295 | 296 | cputms(3) = cputms(3) + (cputime-t0); % end timing MATLAB OP(X) 297 | 298 | if eigs_display 299 | displayRitzValues; 300 | end 301 | 302 | end % while (ido ~= 99) 303 | 304 | t0 = cputime; % start timing post-processing 305 | 306 | if (info < 0) 307 | error('MATLAB:eigs:ARPACKroutineError', ... 308 | 'Error with ARPACK routine %s: info = %d',aupdfun,full(info)); 309 | end % if (info < 0) 310 | 311 | if (nargout >= 2) 312 | rvec = intconvert(true); % compute eigenvectors 313 | else 314 | rvec = intconvert(false); % do not compute eigenvectors 315 | end 316 | 317 | if isrealprob 318 | if issymA 319 | arpackc( eupdfun, rvec, 'A', select, ... 320 | d, v, ldv, sigma, ... 321 | bmat, intconvert(n), whch, nev, tol, resid, ncv, ... 322 | v, ldv, iparam, ipntr, workd, workl, lworkl, info ); 323 | if strcmp(whch,'LM') || strcmp(whch,'LA') 324 | d = flipud(d); 325 | if (rvec == 1) 326 | v(:,1:k) = v(:,k:-1:1); 327 | end 328 | end 329 | if ((strcmp(whch,'SM') || strcmp(whch,'SA')) && (rvec == 0)) 330 | d = flipud(d); 331 | end 332 | else 333 | % If sigma is complex, isrealprob=true and we use [c,z]neupd. 334 | % So use sigmar=sigma and sigmai=0 here in dneupd. 335 | arpackc( eupdfun, rvec, 'A', select, ... 336 | d, di, v, ldv, sigma, 0, workev, ... 337 | bmat, intconvert(n), whch, nev, tol, resid, ncv, ... 338 | v, ldv, iparam, ipntr, workd, workl, lworkl, info ); 339 | d = complex(d,di); 340 | if rvec 341 | d(k+1) = []; 342 | else 343 | zind = find(d == 0); 344 | if isempty(zind) 345 | d = d(k+1:-1:2); 346 | else 347 | d(max(zind)) = []; 348 | d = flipud(d); 349 | end 350 | end 351 | end 352 | else 353 | zsigma = [real(sigma); imag(sigma)]; 354 | arpackc( eupdfun, rvec, 'A', select, ... 355 | zd, zv, ldv, zsigma, workev, ... 356 | bmat, intconvert(n), whch, nev, tol, resid, ncv, zv, ... 357 | ldv, iparam, ipntr, zworkd, workl, lworkl, ... 358 | rwork, info ); 359 | if issymA 360 | d = zd(1:2:end-1); 361 | else 362 | d = complex(zd(1:2:end-1),zd(2:2:end)); 363 | end 364 | v = reshape(complex(zv(1:2:end-1),zv(2:2:end)),[n p]); 365 | end 366 | 367 | flag = processEUPDinfo(nargin<3); 368 | 369 | if (issymA) || (~isrealprob) 370 | if (nargout <= 1) 371 | if isrealprob 372 | varargout{1} = d; 373 | else 374 | varargout{1} = d(k:-1:1,1); 375 | end 376 | else 377 | varargout{1} = v(:,1:k); 378 | varargout{2} = diag(d(1:k,1)); 379 | if (nargout >= 3) 380 | varargout{3} = flag; 381 | end 382 | end 383 | else 384 | if (nargout <= 1) 385 | varargout{1} = d; 386 | else 387 | cplxd = find(di ~= 0); 388 | % complex conjugate pairs of eigenvalues occur together 389 | cplxd = cplxd(1:2:end); 390 | v(:,[cplxd cplxd+1]) = [complex(v(:,cplxd),v(:,cplxd+1)) ... 391 | complex(v(:,cplxd),-v(:,cplxd+1))]; 392 | varargout{1} = v(:,1:k); 393 | varargout{2} = diag(d); 394 | if (nargout >= 3) 395 | varargout{3} = flag; 396 | end 397 | end 398 | end 399 | 400 | if (nargout >= 2) && (mode ~= 3) && ~isempty(B) && BisHpd == true 401 | varargout{1} = RBsolve(varargout{1}); 402 | end 403 | 404 | if ~isempty(B) 405 | if nargout >= 2 406 | varargout{2} = varargout{2}/scaleB; 407 | else 408 | varargout{1} = varargout{1}/scaleB; 409 | end 410 | end 411 | 412 | if BisHpd == true && (nargout >= 2) 413 | vnorms = zeros(k,1); 414 | for ii = 1 : k 415 | vnorms(ii) = scaleB*(varargout{1}(:,ii)'*(Bmtimes(varargout{1}(:,ii)))); 416 | varargout{1}(:,ii) = varargout{1}(:,ii)/sqrt(vnorms(ii)); 417 | end 418 | end 419 | 420 | cputms(4) = cputime-t0; % end timing post-processing 421 | 422 | cputms(5) = sum(cputms(1:4)); % total time 423 | 424 | if (eigs_display == 2) 425 | printTimings; 426 | end 427 | 428 | %-------------------------------------------------------------------------% 429 | % Nested functions 430 | %-------------------------------------------------------------------------% 431 | 432 | % checkInputs error checks the inputs to EIGS and also derives some 433 | % variables from them: 434 | % A may be a matrix or a function applying OP. 435 | % Amatrix is true if A is a matrix, false if A is a function. 436 | % isrealprob is true if all of A, B and sigma are real, false otherwise. 437 | % issymA is true if A is symmetric, false otherwise. 438 | % n is the size of (square) A and B. 439 | % B is [] for the standard problem. Otherwise it may be one of B, CHOL(B) 440 | % or CHOL(B(permB,permB)). 441 | % classAB is single if either A or B is single, otherwise double. 442 | % k is the number of eigenvalues to be computed. 443 | % eigs_sigma is the value for sigma passed in by the user, 'LM' if it was 444 | % unspecified. eigs_sigma may be either a string or a scalar value. 445 | % whch is the ARPACK string corresponding to eigs_sigma and mode. 446 | % sigma is the ARPACK scalar corresponding to eigs_sigma and mode. 447 | % tol is the convergence tolerance. 448 | % maxit is the maximum number of iterations. 449 | % p is the number of Lanczos vectors. 450 | % info is the start value, initialized to 1 or 0 to indicate whether to use 451 | % resid as the start vector or not. 452 | % eigs_display is true if Ritz values should be displayed, false otherwise. 453 | % cholB is true if CHOL(B) was passed in instead of B, false otherwise. 454 | % permB may be [], otherwise it is the permutation in CHOL(B(permB,permB)). 455 | % resid is the start vector if specified and info=1, otherwise all zero. 456 | % useeig is true if we need to use EIG instead of ARPACK, otherwise false. 457 | % afunNargs is the range of EIGS' varargin that are to be passed as 458 | % trailing parameters to the function as in afun(X,P1,P2,...). 459 | function [A,Amatrix,isrealprob,issymA,n,B,classAB,k, ... 460 | eigs_sigma,whch,sigma,tol,maxit,p,info,eigs_display,cholB,... 461 | permB,resid,useeig,afunNargs,style,mode,Afactors,Bfactors] = checkInputs(varargin) 462 | % Process inputs and do error-checking 463 | 464 | % Process the input A or the inputs AFUN and N 465 | % Start to derive some qualities (real, symmetric) about the problem 466 | if isfloat(varargin{1}) 467 | A = varargin{1}; 468 | Amatrix = true; 469 | else 470 | % By checking the function A with fcnchk, we can now use direct 471 | % function evaluation on the result, without resorting to feval 472 | A = fcnchk(varargin{1}); 473 | Amatrix = false; 474 | end 475 | isrealprob = true; 476 | issymA = false; 477 | if Amatrix 478 | isrealprob = isreal(A); 479 | issymA = ishermitian(A); 480 | [m,n] = size(A); 481 | if (m ~= n) 482 | error('MATLAB:eigs:NonSquareMatrixOrFunction',... 483 | 'A must be a square matrix or a function.') 484 | end 485 | else 486 | n = varargin{2}; 487 | nstr = 'Size of problem, ''n'', must be a positive integer.'; 488 | if ~isscalar(n) || ~isreal(n) 489 | error('MATLAB:eigs:NonPosIntSize', nstr) 490 | end 491 | if issparse(n) 492 | n = full(n); 493 | end 494 | if (round(n) ~= n) 495 | warning('MATLAB:eigs:NonPosIntSize',['%s\n ' ... 496 | 'Rounding input size.'],nstr) 497 | n = round(n); 498 | end 499 | end 500 | 501 | % Process the input B and derive the class of the problem. 502 | % Is B present in the eigs call or not? 503 | Bpresent = true; 504 | Bstr = 'Generalized matrix B must be the same size as A.'; 505 | if (nargin < (3-Amatrix)) 506 | B = []; 507 | Bpresent = false; 508 | else 509 | % Is the next input B or K? 510 | B = varargin{3-Amatrix}; 511 | if ~isempty(B) % allow eigs(A,[],k,sigma,opts); 512 | if isscalar(B) 513 | if n ~= 1 514 | % this input is really K and B is not specified 515 | B = []; 516 | Bpresent = false; 517 | else 518 | % This input could be B or K. 519 | % If A is scalar, then the only valid value for k is 1. 520 | % So if this input is scalar, let it be B, namely 521 | % eigs(4,2,...) assumes A=4, B=2, NOT A=4, k=2 522 | if ~isnumeric(B) 523 | error('MATLAB:eigs:BsizeMismatchA', Bstr); 524 | end 525 | % Unless, of course, the scalar is 1, in which case 526 | % assume the that it is meant to be K. 527 | if (B == 1) && ((Amatrix && nargin <= 3) || ... 528 | (~Amatrix && nargin <= 4)) 529 | B = []; 530 | Bpresent = false; 531 | elseif ~isfloat(B) 532 | error('MATLAB:eigs:BsizeMismatchA', Bstr); 533 | end 534 | end 535 | else 536 | % B is a not a scalar. 537 | if ~isfloat(B) || ~isequal(size(B),[n,n]) 538 | error('MATLAB:eigs:BsizeMismatchA', Bstr); 539 | end 540 | isrealprob = isrealprob && isreal(B); 541 | end 542 | end 543 | end 544 | % ARPACK can only handle homogeneous inputs 545 | if Amatrix 546 | classAB = superiorfloat(A,B); 547 | A = cast(A,classAB); 548 | B = cast(B,classAB); 549 | else 550 | if ~isempty(B) 551 | classAB = class(B); 552 | else 553 | classAB = 'double'; 554 | end 555 | end 556 | 557 | % argOffset tells us where to get the eigs inputs K, SIGMA and OPTS. 558 | % If A is really the function afun, then it also helps us find the 559 | % trailing parameters in eigs(afun,n,[B],k,sigma,opts,P1,P2,...) 560 | % Values of argOffset: 561 | % 0: Amatrix is false and Bpresent is true: 562 | % eigs(afun,n,B,k,sigma,opts,P1,P2,...) 563 | % 1: Amatrix and Bpresent are both true, or both false 564 | % eigs(A,B,k,sigma,opts) 565 | % eigs(afun,n,k,sigma,opts,P1,P2,...) 566 | % 2: Amatrix is true and Bpresent is false: 567 | % eigs(A,k,sigma,opts) 568 | argOffset = Amatrix + ~Bpresent; 569 | 570 | if Amatrix && ((nargin - Bpresent)>4) 571 | error('MATLAB:eigs:TooManyInputs', 'Too many inputs.') 572 | end 573 | 574 | % Process the input K. 575 | if (nargin < (4-argOffset)) 576 | k = min(n,6); 577 | else 578 | k = varargin{4-argOffset}; 579 | kstr = ['Number of eigenvalues requested, k, must be a' ... 580 | ' positive integer <= n.']; 581 | if ~isnumeric(k) || ~isscalar(k) || ~isreal(k) || (k>n) 582 | error('MATLAB:eigs:NonIntegerEigQty', kstr) 583 | end 584 | if issparse(k) 585 | k = full(k); 586 | end 587 | if (round(k) ~= k) 588 | warning('MATLAB:eigs:NonIntegerEigQty',['%s\n ' ... 589 | 'Rounding number of eigenvalues.'],kstr) 590 | k = round(k); 591 | end 592 | end 593 | 594 | % Process the input SIGMA and derive ARPACK values whch and sigma. 595 | % eigs_sigma is the value documented in the help as "SIGMA" that is 596 | % passed in to EIGS. eigs_sigma may be either a scalar, including 0, 597 | % or a string, including 'SM'. 598 | % In ARPACK, eigs_sigma corresponds to two variables: 599 | % 1. which, called "whch" to avoid conflict with MATLAB's function 600 | % 2. sigma 601 | % whch is always a string. sigma is always a scalar. 602 | % Valid combinations are shown below. Note eigs_sigma = 0/'SM' has 603 | % the same sigma/whch values as eigs_sigma='LM' (default) so these 604 | % must be distinguished by the mode. 605 | % eigs_sigma = 'SM' or 0 => sigma = 0, whch = 'LM' (mode=3) 606 | % eigs_sigma is a string not 'SM' => sigma = 0, whch = eigs_sigma (mode=1) 607 | % eigs_sigma is any scalar => sigma = eigs_sigma, whch = 'LM' 608 | % (mode=1) 609 | whchstr = 'Eigenvalue range sigma must be a valid 2-element string.'; 610 | if (nargin < (5-argOffset)) 611 | % default: eigs 'LM' => ARPACK which='LM', sigma=0 612 | eigs_sigma = 'LM'; 613 | whch = 'LM'; 614 | sigma = 0; 615 | else 616 | eigs_sigma = varargin{5-argOffset}; 617 | if ischar(eigs_sigma) 618 | % eigs(string) => ARPACK which=string, sigma=0 619 | if ~isequal(size(eigs_sigma),[1,2]) 620 | error('MATLAB:eigs:EigenvalueRangeNotValid', ... 621 | [whchstr '\nFor real symmetric A, the' ... 622 | ' choices are ''%s'', ''%s'', ''%s'', ''%s'' or ''%s''.' ... 623 | '\nFor non-symmetric or complex' ... 624 | ' A, the choices are ''%s'', ''%s'', ''%s'', ''%s'',' ... 625 | ' ''%s'' or ''%s''.\n'], ... 626 | 'LM','SM','LA','SA','BE','LM','SM','LR','SR','LI','SI') 627 | end 628 | eigs_sigma = upper(eigs_sigma); 629 | if strcmp(eigs_sigma,'SM') 630 | % eigs('SM') => ARPACK which='LM', sigma=0 631 | whch = 'LM'; 632 | else 633 | % eigs(string), where string~='SM' => ARPACK which=string, sigma=0 634 | whch = eigs_sigma; 635 | end 636 | sigma = zeros(classAB); 637 | else 638 | % eigs(scalar) => ARPACK which='LM', sigma=scalar 639 | if ~isfloat(eigs_sigma) || ~isscalar(eigs_sigma) 640 | error('MATLAB:eigs:EigenvalueShiftNonScalar',... 641 | 'Eigenvalue shift sigma must be a scalar.') 642 | end 643 | sigma = eigs_sigma; 644 | if issparse(sigma) 645 | sigma = full(sigma); 646 | end 647 | sigma = cast(sigma,classAB); 648 | isrealprob = isrealprob && isreal(sigma); 649 | whch = 'LM'; 650 | end 651 | end 652 | 653 | % Process the input OPTS and derive some ARPACK values. 654 | % ARPACK's minimum tolerance is eps/2 ([S/D]LAMCH's EPS) 655 | tol = eps(classAB); 656 | maxit = []; 657 | p = []; 658 | style = []; 659 | % Always use resid as the start vector, whether it is OPTS.v0 or 660 | % randomly generated within eigs. We default resid to empty here. 661 | % If the user does not initialize it, we provide a random residual 662 | % below. 663 | info = intconvert(1); 664 | resid = []; 665 | eigs_display = 1; 666 | cholB = false; % do we have B or its Cholesky factor? 667 | permB = []; % if cholB, is it chol(B), or chol(B(permB,permB))? 668 | if (nargin >= (6-argOffset)) 669 | opts = varargin{6-argOffset}; 670 | if ~isa(opts,'struct') 671 | error('MATLAB:eigs:OptionsNotStructure',... 672 | 'Options argument must be a structure.') 673 | end 674 | if isfield(opts,'issym') && ~Amatrix 675 | issymA = opts.issym; 676 | if (issymA ~= false) && (issymA ~= true) 677 | error('MATLAB:eigs:InvalidOptsIssym', ... 678 | 'opts.issym must be true or false.') 679 | end 680 | end 681 | if isfield(opts,'isreal') && ~Amatrix 682 | if (opts.isreal ~= false) && (opts.isreal ~= true) 683 | error('MATLAB:eigs:InvalidOptsIsreal', ... 684 | 'opts.isreal must be true or false.') 685 | end 686 | isrealprob = isrealprob && opts.isreal; 687 | end 688 | if ~isempty(B) && (isfield(opts,'cholB') || isfield(opts,'permB')) 689 | if isfield(opts,'cholB') 690 | cholB = opts.cholB; 691 | if (cholB ~= false) && (cholB ~= true) 692 | error('MATLAB:eigs:InvalidOptsCholB', ... 693 | 'opts.cholB must be true or false.') 694 | end 695 | if isfield(opts,'permB') 696 | if issparse(B) && cholB 697 | permB = opts.permB; 698 | if ~isvector(permB) || ~isequal(sort(permB(:)),(1:n)') 699 | error('MATLAB:eigs:InvalidOptsPermB',... 700 | 'opts.permB must be a permutation of 1:n.') 701 | end 702 | else 703 | warning('MATLAB:eigs:IgnoredOptionPermB', ... 704 | ['Ignoring opts.permB since B is not its sparse' ... 705 | ' Cholesky factor.']) 706 | end 707 | end 708 | end 709 | end 710 | if isfield(opts,'tol') 711 | if ~isfloat(tol) || ~isscalar(opts.tol) || ~isreal(opts.tol) || (opts.tol<=0) 712 | error('MATLAB:eigs:InvalidOptsTol',... 713 | ['Convergence tolerance opts.tol must be a strictly' ... 714 | ' positive real scalar.']) 715 | end 716 | tol = cast(full(opts.tol),classAB); 717 | end 718 | if isfield(opts,'p') 719 | p = opts.p; 720 | pstr = ['Number of basis vectors opts.p must be a positive' ... 721 | ' integer <= n.']; 722 | if ~isnumeric(p) || ~isscalar(p) || ~isreal(p) || (p<=0) || (p>n) 723 | error('MATLAB:eigs:InvalidOptsP', pstr) 724 | end 725 | if issparse(p) 726 | p = full(p); 727 | end 728 | if (round(p) ~= p) 729 | warning('MATLAB:eigs:NonIntegerVecQty',['%s\n ' ... 730 | 'Rounding number of basis vectors.'],pstr) 731 | p = round(p); 732 | end 733 | end 734 | if isfield(opts,'maxit') 735 | maxit = opts.maxit; 736 | str = ['Maximum number of iterations opts.maxit must be' ... 737 | ' a positive integer.']; 738 | if ~isnumeric(maxit) || ~isscalar(maxit) || ~isreal(maxit) || (maxit<=0) 739 | error('MATLAB:eigs:OptsMaxitNotPosInt', str) 740 | end 741 | if issparse(maxit) 742 | maxit = full(maxit); 743 | end 744 | if (round(maxit) ~= maxit) 745 | warning('MATLAB:eigs:NonIntegerIterationQty',['%s\n ' ... 746 | 'Rounding number of iterations.'],str) 747 | maxit = round(maxit); 748 | end 749 | end 750 | if isfield(opts,'v0') 751 | if ~isfloat(opts.v0) || ~isequal(size(opts.v0),[n,1]) 752 | error('MATLAB:eigs:WrongSizeOptsV0',... 753 | 'Start vector opts.v0 must be n-by-1.') 754 | end 755 | if isrealprob 756 | if ~isreal(opts.v0) 757 | error('MATLAB:eigs:NotRealOptsV0',... 758 | 'Start vector opts.v0 must be real for real problems.') 759 | end 760 | resid(1:n,1) = full(opts.v0); 761 | else 762 | resid(2:2:2*n,1) = full(imag(opts.v0)); 763 | resid(1:2:(2*n-1),1) = full(real(opts.v0)); 764 | end 765 | end 766 | if isfield(opts,'disp') 767 | eigs_display = opts.disp; 768 | dispstr = 'Diagnostic level opts.disp must be an integer.'; 769 | if ~isnumeric(eigs_display) || ~isscalar(eigs_display) || ... 770 | ~isreal(eigs_display) || (eigs_display<0) 771 | error('MATLAB:eigs:NonIntegerDiagnosticLevel', dispstr) 772 | end 773 | if (round(eigs_display) ~= eigs_display) 774 | warning('MATLAB:eigs:NonIntegerDiagnosticLevel', ... 775 | '%s\n Rounding diagnostic level.',dispstr) 776 | eigs_display = round(eigs_display); 777 | end 778 | end 779 | if isfield(opts,'cheb') 780 | error('MATLAB:eigs:ObsoleteOptionCheb', ... 781 | 'Polynomial acceleration opts.cheb is an obsolete option.'); 782 | end 783 | if isfield(opts,'stagtol') 784 | error('MATLAB:eigs:ObsoleteOptionStagtol', ... 785 | 'Stagnation tolerance opts.stagtol is an obsolete option.'); 786 | end 787 | if isfield(opts,'style') 788 | style = opts.style; 789 | str = 'style must be ''S'' or ''G''.'; 790 | if ~ischar(style) 791 | error('MATLAB:eigs:InvalidStyle',str); 792 | elseif ~(strcmp(style,'S') || strcmp(style,'G')) 793 | error('MATLAB:eigs:InvalidStyle',str); 794 | end 795 | end 796 | end 797 | if (isempty(resid)) 798 | if isrealprob 799 | resid = cast(rand(n,1),classAB); 800 | else 801 | resid = cast(rand(2*n,1),classAB); 802 | end 803 | end 804 | 805 | afunNargs = zeros(1,0); 806 | if ~Amatrix 807 | % The trailing parameters for afun start at varargin{7-argOffset} 808 | % in eigs(afun,n,[B],k,sigma,opts,P1,P2,...). If there are no 809 | % trailing parameters in eigs, then afunNargs is a 1-by-0 empty 810 | % and no trailing parameters are passed to afun(x) 811 | afunNargs = 7-argOffset:nargin; 812 | end 813 | 814 | % Now that OPTS has been processed, do final error checking and 815 | % assign ARPACK variables 816 | 817 | % Extra check on input B 818 | if ~isempty(B) 819 | % B must be symmetric (Hermitian) positive (semi-)definite 820 | if cholB 821 | if ~isequal(triu(B),B) 822 | error('MATLAB:eigs:BNotChol', ... 823 | 'opts.CHOLB specified, but B is not upper triangular.'); 824 | end 825 | end 826 | end 827 | 828 | if isempty(style) 829 | if strcmp(eigs_sigma,'SM') || isscalar(eigs_sigma) || ~isempty(B) 830 | style = 'G'; 831 | else 832 | style = 'S'; 833 | end 834 | end 835 | 836 | if ~isempty(B) 837 | scaleB = norm(B,'fro')/sqrt(n); 838 | scaleB = 2^(floor(log2(scaleB+1))); 839 | B = B/scaleB; 840 | if cholB 841 | scaleB = scaleB^2; 842 | end 843 | if isscalar(eigs_sigma) 844 | sigma = scaleB*eigs_sigma; 845 | end 846 | end 847 | 848 | 849 | if strcmp(eigs_sigma,'SM') || ~ischar(eigs_sigma) 850 | % eigs(A,B,k,scalarSigma) or eigs(A,B,k,'SM'), B may be [] 851 | % Note: sigma must be real for [s,d]saupd and [s,d]naupd 852 | % If sigma is complex, even if A and B are both real, we use 853 | % [c,z]naupd. 854 | % This means that mode=3 in [s,d]naupd, which has 855 | % OP = real(inv(A - sigma*M)*M) and B = M 856 | % reduces to the same OP as [s,d]saupd and [c,z]naupd. 857 | % A*x = lambda*M*x, M symmetric (positive) semi-definite 858 | % => OP = inv(A - sigma*M)*M and B = M 859 | % => shift-and-invert mode 860 | mode = 3; 861 | elseif strcmp(style,'S') 862 | % eigs(A,k,stringSigma) or eigs(A,[],k,stringSigma), 863 | % stringSigma~='SM' 864 | % A*x = lambda*x 865 | % => OP = A and B = I 866 | mode = 1; 867 | else 868 | % eigs(A,B,k,stringSigma), stringSigma~='SM' 869 | % A*x = lambda*B*x 870 | % => OP = inv(B)*A and use standard inner product. 871 | mode = 2; 872 | end 873 | 874 | BisHpd = false; 875 | if cholB || (~isempty(B) && ishermitian(B)) 876 | % The reordering permutation permB is [] unless B is sparse 877 | [RB,RBT,permB,BisHpd] = CHOLfactorB; 878 | if mode == 3 && ~cholB 879 | RB = []; RBT = []; permB = []; 880 | end 881 | end 882 | 883 | qqB = []; 884 | if BisHpd == false && (mode == 1 || mode == 2) 885 | [LB,UB,ppB,qqB,dgB] = LUfactorB; 886 | end 887 | 888 | Bfactors = []; 889 | if ~isempty(B) 890 | if BisHpd == true 891 | Bfactors = struct('RB',RB,'RBT',RBT,'permB',permB,'BisHpd',BisHpd); 892 | elseif (mode == 1 || mode == 2) 893 | Bfactors = struct('LB',LB,'UB',UB,'ppB',ppB,'qqB',qqB,'dgB',dgB,'BisHpd',BisHpd); 894 | end 895 | end 896 | 897 | Afactors = []; 898 | qq = []; 899 | if (mode == 3) && Amatrix % need lu(A-sigma*B) 900 | % The reordering permutation permAsB is [] unless A-sigma*B is sparse 901 | [L,U,pp,qq,dgAsB] = LUfactorAminusSigmaB; 902 | Afactors = struct('L',L,'U',U,'pp',pp,'qq',qq,'dgAsB',dgAsB); 903 | end % if (mode == 3) && Amatrix 904 | 905 | % under these conditions, OP must be unsymmetric 906 | % note that OP = inv(A-\sigma*B)*B IS symmetric if A is symmetric 907 | % and B-inner product is used! 908 | if ~isempty(B) && (BisHpd == false || (strcmp(style,'S') && mode == 3)) 909 | issymA = false; 910 | end 911 | % Extra check on input K 912 | % We fall back on using the full EIG code if K is too large. 913 | useeig = false; 914 | if isrealprob && issymA 915 | knstr = sprintf(['For real symmetric problems, must have' ... 916 | ' number of eigenvalues k < n.\n']); 917 | else 918 | knstr = sprintf(['For nonsymmetric and complex problems,' ... 919 | ' must have number of eigenvalues k < n-1.\n']); 920 | end 921 | if isempty(B) 922 | knstr = [knstr 'Using eig(full(A)) instead.']; 923 | else 924 | knstr = [knstr 'Using eig(full(A),full(B)) instead.']; 925 | end 926 | if (k == 0) 927 | useeig = true; 928 | end 929 | if isrealprob && issymA 930 | if (k > n-1) 931 | if (n >= 6) 932 | warning('MATLAB:eigs:TooManyRequestedEigsForRealSym', ... 933 | '%s',knstr) 934 | end 935 | useeig = true; 936 | end 937 | else 938 | if (k > n-2) 939 | if (n >= 7) 940 | warning('MATLAB:eigs:TooManyRequestedEigsForComplexNonsym', ... 941 | '%s',knstr) 942 | end 943 | useeig = true; 944 | end 945 | end 946 | 947 | % Extra check on input SIGMA 948 | if isrealprob && issymA 949 | if ~isreal(sigma) 950 | error('MATLAB:eigs:ComplexShiftForRealSymProblem',... 951 | ['For real symmetric problems, eigenvalue shift sigma must' ... 952 | ' be real.']) 953 | end 954 | else 955 | if ~isrealprob && issymA && ~isreal(sigma) 956 | warning('MATLAB:eigs:ComplexShiftForHermitianProblem', ... 957 | ['Complex eigenvalue shift sigma on a Hermitian problem' ... 958 | ' (all real eigenvalues).']) 959 | end 960 | end 961 | if isrealprob && issymA 962 | if strcmp(whch,'LR') 963 | whch = 'LA'; 964 | warning('MATLAB:eigs:SigmaChangedToLA', ... 965 | ['For real symmetric problems, sigma value ''LR''' ... 966 | ' (Largest Real) is now ''LA'' (Largest Algebraic).']) 967 | end 968 | if strcmp(whch,'SR') 969 | whch = 'SA'; 970 | warning('MATLAB:eigs:SigmaChangedToSA', ... 971 | ['For real symmetric problems, sigma value ''SR''' ... 972 | ' (Smallest Real) is now ''SA'' (Smallest Algebraic).']) 973 | end 974 | if ~ismember(whch,{'LM', 'SM', 'LA', 'SA', 'BE'}) 975 | error('MATLAB:eigs:EigenvalueRangeNotValid', ... 976 | [whchstr '\nFor real symmetric A, the' ... 977 | ' choices are ''%s'', ''%s'', ''%s'', ''%s'' or ''%s''.'], ... 978 | 'LM','SM','LA','SA','BE'); 979 | end 980 | else 981 | if strcmp(whch,'BE') 982 | warning('MATLAB:eigs:SigmaChangedToLM', ... 983 | ['Sigma value ''BE'' is now only available for real' ... 984 | ' symmetric problems. Computing ''LM'' eigenvalues instead.']) 985 | whch = 'LM'; 986 | end 987 | if ~ismember(whch,{'LM', 'SM', 'LR', 'SR', 'LI', 'SI'}) 988 | error('MATLAB:eigs:EigenvalueRangeNotValid', ... 989 | [whchstr '\nFor non-symmetric or complex' ... 990 | ' A, the choices are ''%s'', ''%s'', ''%s'', ''%s'',' ... 991 | ' ''%s'' or ''%s''.\n'],'LM','SM','LR','SR','LI','SI'); 992 | end 993 | end 994 | 995 | % The remainder of the error checking does not apply for the large 996 | % values of K that force us to use full EIG instead of ARPACK. 997 | if useeig 998 | return 999 | end 1000 | 1001 | % Extra check on input OPTS.p 1002 | if isempty(p) 1003 | if isrealprob && ~issymA 1004 | p = min(max(2*k+1,20),n); 1005 | else 1006 | p = min(max(2*k,20),n); 1007 | end 1008 | else 1009 | if isrealprob && issymA 1010 | if (p <= k) 1011 | error('MATLAB:eigs:InvalidOptsPforRealSymProb',... 1012 | ['For real symmetric problems, must have number of' ... 1013 | ' basis vectors opts.p > k.']) 1014 | end 1015 | else 1016 | if (p <= k+1) 1017 | error('MATLAB:eigs:InvalidOptsPforComplexOrNonSymProb',... 1018 | ['For nonsymmetric and complex problems, must have number of' ... 1019 | ' basis vectors opts.p > k+1.']) 1020 | end 1021 | end 1022 | end 1023 | 1024 | % Extra check on input OPTS.maxit 1025 | if isempty(maxit) 1026 | maxit = max(300,ceil(2*n/max(p,1))); 1027 | end 1028 | 1029 | 1030 | % Nested functions in checkInputs 1031 | %-------------------------------------------------------------------------% 1032 | function [RB,RBT,ppB,BisHpd] = CHOLfactorB 1033 | % permB may be [] (from checkInputs) if the problem is not sparse 1034 | % or if it was not passed in as opts.permB 1035 | ppB = permB; 1036 | if cholB 1037 | % CHOL(B) was passed in as B 1038 | RB = B; 1039 | RBT = B'; 1040 | BisHpd = true; 1041 | else 1042 | % CHOL(B) was not passed into EIGS 1043 | if ~isempty(B) 1044 | % Algorithm requires CHOL(B) to be computed 1045 | if issparse(B) 1046 | ppB = symamd(B); 1047 | [RB,idxB] = chol(B(ppB,ppB)); 1048 | else 1049 | [RB,idxB] = chol(B); 1050 | end 1051 | if mode == 3 1052 | RB = []; ppB = []; 1053 | end 1054 | RBT = RB'; 1055 | if (idxB == 0) 1056 | BisHpd = true; 1057 | elseif mode == 3 && isreal(B) 1058 | % LDL decomposition is only for 'SM' eigenvalues of the 1059 | % pair (A,B) where B is Hermitian positive 1060 | % semi-definite; in this case, as ARPACK users' guide 1061 | % suggests, one should still use B-(semi)inner product 1062 | [LB,DB,pvB] = ldl(B,'vector'); %#ok 1063 | BisHpd = checkTridiagForHSD(diag(DB), diag(DB,1)); 1064 | else 1065 | BisHpd = false; 1066 | end 1067 | end 1068 | end 1069 | if ~isempty(B) && issparse(B) 1070 | tmp = speye(length(B)); 1071 | ppB = tmp(ppB,1:length(B)); 1072 | end 1073 | end % CHOLfactorB 1074 | %-------------------------------------------------------------------------% 1075 | function [LB,UB,ppB,qqB,dgB] = LUfactorB 1076 | % LU factor B, including a reordering perm if it is sparse 1077 | if issparse(B) 1078 | [LB,UB,ppB,qqB,dgB] = lu(B); 1079 | else 1080 | [LB,UB,ppB] = lu(B,'vector'); 1081 | qqB = []; dgB = []; 1082 | end 1083 | % Warn if lu(B) is ill-conditioned 1084 | dUB = diag(UB); 1085 | if any(dUB == 0) || any(diag(LB) == 0) 1086 | error('MATLAB:eigs:SingularB', ... 1087 | ['B is singular.\nUnable to compute the specified eigenvalues'... 1088 | ' because infinite eigenvalue(s) exist']); 1089 | end 1090 | rcondestUB = full(min(abs(dUB)) / max(abs(dUB))); 1091 | if (rcondestUB < eps) 1092 | warning('MATLAB:eigs:IllConditionedB',... 1093 | ['B has small reciprocal condition' ... 1094 | ' estimate: %f\n' ... 1095 | ' indicating that B^{-1}A might not be applied accurately.\n' ... 1096 | ' and there may be infinite eigenvalue(s).\n'],... 1097 | rcondestUB); 1098 | end 1099 | end % LUfactorB 1100 | 1101 | %-------------------------------------------------------------------------% 1102 | function [L,U,pp,qq,dgAsB] = LUfactorAminusSigmaB 1103 | % LU factor A-sigma*B, including a reordering perm if it is sparse 1104 | if sigma == 0 1105 | AsB = A; 1106 | elseif isempty(B) 1107 | if issparse(A) 1108 | AsB = A - sigma * speye(n); 1109 | else 1110 | AsB = A - sigma * eye(n); 1111 | end 1112 | else 1113 | if cholB 1114 | if issparse(B) 1115 | AsB = A - sigma * checkInputBmtimes(speye(n)); 1116 | else 1117 | AsB = A - sigma * checkInputBmtimes(eye(n)); 1118 | end 1119 | else 1120 | AsB = A - sigma * B; 1121 | end 1122 | end 1123 | if issparse(AsB) 1124 | [L,U,pp,qq,dgAsB] = lu(AsB); 1125 | else 1126 | [L,U,pp] = lu(AsB,'vector'); 1127 | qq = []; dgAsB = []; 1128 | end 1129 | % Warn if lu(A-sigma*B) is ill-conditioned 1130 | % => sigma is close to an exact eigenvalue of (A,B) 1131 | if isempty(B) 1132 | ds = '(A-sigma*I)'; 1133 | else 1134 | ds = '(A-sigma*B)'; 1135 | end 1136 | dU = diag(U); 1137 | if any(dU == 0) || any(diag(L) == 0) 1138 | error('MATLAB:eigs:AminusBSingular', ... 1139 | [ds 'is singular. The shift is an eigenvalue.\n' ... 1140 | 'Try to use some other shift please.\n']); 1141 | end 1142 | rcondestU = full(min(abs(dU)) / max(abs(dU))); 1143 | if (rcondestU < eps) 1144 | warning('MATLAB:eigs:SigmaNearExactEig',... 1145 | [ds ' has small reciprocal condition' ... 1146 | ' estimate: %f\n' ... 1147 | ' indicating that sigma is near an exact' ... 1148 | ' eigenvalue.\n The algorithm may not converge unless' ... 1149 | ' you try a new value for sigma.\n'], ... 1150 | rcondestU); 1151 | end 1152 | end % LUfactorAminusSigmaB 1153 | 1154 | %-------------------------------------------------------------------------% 1155 | function v = checkInputBmtimes(u) 1156 | % Matrix-vector multiply v = B*u 1157 | if cholB % use B's cholesky factor and its transpose 1158 | if ~isempty(permB) 1159 | v = permB'*(RBT * (RB * (permB*u))); 1160 | else 1161 | v = RBT * (RB * u); 1162 | end 1163 | else 1164 | v = B * u; 1165 | end 1166 | end 1167 | 1168 | end % checkInputs 1169 | 1170 | %-------------------------------------------------------------------------% 1171 | function fullEig(nOutputs) 1172 | % Use EIG(FULL(A)) or EIG(FULL(A),FULL(B)) instead of ARPACK 1173 | if ~isempty(B) 1174 | B = Bmtimes(eye(n)); 1175 | B = B*scaleB; 1176 | end 1177 | if isfloat(A) 1178 | if issparse(A); 1179 | A = full(A); 1180 | end 1181 | else 1182 | % A is specified by a function. 1183 | % Form the matrix A by applying the function. 1184 | if ischar(eigs_sigma) && ~strcmp(eigs_sigma,'SM') 1185 | % A is a function multiplying A*x 1186 | AA = eye(n); 1187 | for i = 1:n 1188 | AA(:,i) = A(AA(:,i),varargin{afunNargs}); 1189 | end 1190 | A = AA; 1191 | else 1192 | if (isfloat(eigs_sigma) && eigs_sigma == 0) || strcmp(eigs_sigma,'SM') 1193 | % A is a function solving A\x 1194 | invA = eye(n); 1195 | for i = 1:n 1196 | invA(:,i) = A(invA(:,i),varargin{afunNargs}); 1197 | end 1198 | A = eye(n) / invA; 1199 | else 1200 | % A is a function solving (A-sigma*B)\x 1201 | % B may be [], indicating the identity matrix 1202 | % U = (A-sigma*B)\sigma*B 1203 | % => (A-sigma*B)*U = sigma*B 1204 | % => A*U = sigma*B(U + eye(n)) 1205 | % => A = sigma*B(U + eye(n)) / U 1206 | if isempty(B) 1207 | sB = eigs_sigma*eye(n); 1208 | else 1209 | sB = eigs_sigma*B; 1210 | end 1211 | U = zeros(n,n); 1212 | for i = 1:n 1213 | U(:,i) = A(sB(:,i),varargin{afunNargs}); 1214 | end 1215 | A = sB*(U+eye(n)) / U; 1216 | end 1217 | end 1218 | end 1219 | 1220 | if isempty(B) 1221 | eigInputs = {A}; 1222 | else 1223 | eigInputs = {A,B}; 1224 | end 1225 | % Now with full floating point matrices A and B, use EIG: 1226 | if (nOutputs <= 1) 1227 | d = eig(eigInputs{:}); 1228 | else 1229 | [V,D] = eig(eigInputs{:}); 1230 | d = diag(D); 1231 | end 1232 | 1233 | % Grab the eigenvalues we want, based on sigma 1234 | firstKindices = 1:k; 1235 | lastKindices = n:-1:n-k+1; 1236 | if ischar(eigs_sigma) 1237 | switch eigs_sigma 1238 | case 'LM' 1239 | [ignore,ind] = sort(abs(d)); 1240 | range = lastKindices; 1241 | case 'SM' 1242 | [ignore,ind] = sort(abs(d)); 1243 | range = firstKindices; 1244 | case 'LA' 1245 | [ignore,ind] = sort(d); 1246 | range = lastKindices; 1247 | case 'SA' 1248 | [ignore,ind] = sort(d); 1249 | range = firstKindices; 1250 | case 'LR' 1251 | [ignore,ind] = sort(abs(real(d))); 1252 | range = lastKindices; 1253 | case 'SR' 1254 | [ignore,ind] = sort(abs(real(d))); 1255 | range = firstKindices; 1256 | case 'LI' 1257 | [ignore,ind] = sort(abs(imag(d))); 1258 | range = lastKindices; 1259 | case 'SI' 1260 | [ignore,ind] = sort(abs(imag(d))); 1261 | range = firstKindices; 1262 | case 'BE' 1263 | [ignore,ind] = sort(abs(d)); 1264 | range = [1:floor(k/2), n-ceil(k/2)+1:n]; 1265 | otherwise 1266 | error('MATLAB:eigs:fullEigSigma','Unknown value of sigma'); 1267 | end 1268 | else 1269 | % sigma is a scalar 1270 | [ignore,ind] = sort(abs(d-eigs_sigma)); 1271 | range = 1:k; 1272 | end 1273 | 1274 | if (nOutputs <= 1) 1275 | varargout{1} = d(ind(range)); 1276 | else 1277 | varargout{1} = V(:,ind(range)); 1278 | varargout{2} = D(ind(range),ind(range)); 1279 | if (nOutputs == 3) 1280 | % flag indicates "convergence" 1281 | varargout{3} = 0; 1282 | end 1283 | end 1284 | 1285 | end % FULLEIG 1286 | 1287 | 1288 | %-------------------------------------------------------------------------% 1289 | function cols = checkIpntr 1290 | % Check that ipntr returned from ARPACK refers to the start of a 1291 | % column of workd. 1292 | if (ido == 1) && (mode == 3) && strcmp(style,'G') 1293 | inds = double(ipntr(1:3)); 1294 | else 1295 | inds = double(ipntr(1:2)); 1296 | end 1297 | rows = mod(inds-1,n)+1; 1298 | cols = (inds-rows)/n+1; 1299 | if ~all(rows==1) 1300 | error('MATLAB:eigs:ipntrMismatchWorkdColumn', ... 1301 | ['One of ipntr(1:3) does not refer to the start' ... 1302 | ' of a column of the %d-by-3 array workd.'],n) 1303 | end 1304 | end % checkIpntr 1305 | 1306 | %-------------------------------------------------------------------------% 1307 | function v = Amtimes(u) 1308 | % Matrix-vector multiply v = A*u 1309 | if Amatrix 1310 | v = A * u; 1311 | else % A is a function 1312 | v = A(u,varargin{afunNargs}); 1313 | if isrealprob && ~isreal(v) 1314 | error('MATLAB:eigs:complexFunction', ... 1315 | 'AFUN is complex; set opts.isreal = false.'); 1316 | end 1317 | end 1318 | end 1319 | 1320 | %-------------------------------------------------------------------------% 1321 | function v = Bmtimes(u) 1322 | % Matrix-vector multiply v = B*u 1323 | if cholB % use B's cholesky factor and its transpose 1324 | if ~isempty(permB) 1325 | v = permB'*(RBT * (RB * (permB*u))); 1326 | else 1327 | v = RBT * (RB * u); 1328 | end 1329 | else 1330 | v = B * u; 1331 | end 1332 | end 1333 | 1334 | %-------------------------------------------------------------------------% 1335 | function v = RBsolve(u) 1336 | % Solve v = RB\u for v 1337 | if issparse(B) 1338 | if ~isempty(permB) 1339 | v = permB'*(RB \ u); 1340 | else 1341 | v = RB \ u; 1342 | end 1343 | else 1344 | RBopts.UT = true; 1345 | v = linsolve(RB,u,RBopts); 1346 | end 1347 | end 1348 | 1349 | %-------------------------------------------------------------------------% 1350 | function v = RBTsolve(u) 1351 | % Solve v = RB'\u for v 1352 | if issparse(B) 1353 | if ~isempty(permB) 1354 | v = RBT \ (permB*u); 1355 | else 1356 | v = RBT \ u; 1357 | end 1358 | else 1359 | RBTopts.LT = true; 1360 | v = linsolve(RBT,u,RBTopts); 1361 | end 1362 | end 1363 | 1364 | %-------------------------------------------------------------------------% 1365 | function v = AminusSigmaBsolve(u) 1366 | % Solve v = (A-sigma*B)\u for v 1367 | if Amatrix 1368 | if ~isempty(dgAsB) 1369 | % use LU reordering permAsB 1370 | v = qq*(U \ (L \ (pp*(dgAsB\u)))); 1371 | else 1372 | v = U \ (L \ u(pp)); 1373 | end 1374 | else % A is a function 1375 | v = A(u,varargin{afunNargs}); 1376 | if isrealprob && ~isreal(v) 1377 | error('MATLAB:eigs:complexFunction', ... 1378 | 'AFUN is complex; set opts.isreal = false.'); 1379 | end 1380 | end 1381 | end % AminusSigmaBsolve 1382 | %-------------------------------------------------------------------------% 1383 | function v = Bsolve(u) 1384 | % Solve v = (A-sigma*B)\u for v 1385 | if ~isempty(dgB) 1386 | % use LU reordering permAsB 1387 | v = qqB*(UB \ (LB \ (ppB*(dgB\u)))); 1388 | else 1389 | v = UB \ (LB \ u(ppB)); 1390 | end 1391 | end % AminusSigmaBsolve 1392 | 1393 | %-------------------------------------------------------------------------% 1394 | function displayRitzValues 1395 | % Display a few Ritz values at the current iteration 1396 | iter = double(ipntr(15)); 1397 | if (iter > eigs_iter) && (ido ~= 99) 1398 | eigs_iter = iter; 1399 | ds = sprintf(['Iteration %d: a few Ritz values of the' ... 1400 | ' %d-by-%d matrix:'],iter,p,p); 1401 | disp(ds) 1402 | if isrealprob 1403 | if issymA 1404 | dispvec = workl(double(ipntr(6))+(0:p-1)); 1405 | if strcmp(whch,'BE') 1406 | % roughly k Large eigenvalues and k Small eigenvalues 1407 | disp(dispvec(max(end-2*k+1,1):end)) 1408 | else 1409 | % k eigenvalues 1410 | disp(dispvec(max(end-k+1,1):end)) 1411 | end 1412 | else 1413 | dispvec = complex(workl(double(ipntr(6))+(0:p-1)), ... 1414 | workl(double(ipntr(7))+(0:p-1))); 1415 | % k+1 eigenvalues (keep complex conjugate pairs together) 1416 | disp(dispvec(max(end-k,1):end)) 1417 | end 1418 | else 1419 | dispvec = complex(workl(2*double(ipntr(6))-1+(0:2:2*(p-1))), ... 1420 | workl(2*double(ipntr(6))+(0:2:2*(p-1)))); 1421 | disp(dispvec(max(end-k+1,1):end)) 1422 | end 1423 | end 1424 | end 1425 | 1426 | %-------------------------------------------------------------------------% 1427 | function flag = processEUPDinfo(warnNonConvergence) 1428 | % Process the info flag returned by the ARPACK routine **eupd 1429 | flag = 0; 1430 | if (info ~= 0) 1431 | es = ['Error with ARPACK routine ' eupdfun ':\n']; 1432 | switch double(info) 1433 | case 2 1434 | ss = sum(select); 1435 | if (ss < k) 1436 | error('MATLAB:eigs:ARPACKroutineError02ssLTk', ... 1437 | [es 'The logical variable select was only set' ... 1438 | ' with %d 1''s instead of nconv=%d (k=%d).\n' ... 1439 | 'Please report this to the ARPACK authors at' ... 1440 | ' arpack@caam.rice.edu.'], ... 1441 | ss,double(iparam(5)),k) 1442 | else 1443 | error('MATLAB:eigs:ARPACKroutineError02', ... 1444 | [es 'The LAPACK reordering routine %strsen' ... 1445 | ' did not return all %d eigenvalues.'], ... 1446 | aupdfun(1),k); 1447 | end 1448 | case 1 1449 | error('MATLAB:eigs:ARPACKroutineError01', ... 1450 | [es 'The Schur form could not be reordered by the' ... 1451 | ' LAPACK routine %strsen.\nPlease report this to the' ... 1452 | ' ARPACK authors at arpack@caam.rice.edu.'], ... 1453 | aupdfun(1)) 1454 | case -14 1455 | error('MATLAB:eigs:ARPACKroutineErrorMinus14', ... 1456 | [es aupdfun ... 1457 | ' did not find any eigenvalues to sufficient accuracy.']); 1458 | otherwise 1459 | error('MATLAB:eigs:ARPACKroutineError', ... 1460 | [es 'info = %d. Please consult the ARPACK Users''' ... 1461 | ' Guide for more information.'],full(info)); 1462 | end 1463 | else 1464 | nconv = double(iparam(5)); 1465 | if (nconv == 0) 1466 | if (warnNonConvergence) 1467 | warning('MATLAB:eigs:NoEigsConverged', ... 1468 | 'None of the %d requested eigenvalues converged.',k) 1469 | else 1470 | flag = 1; 1471 | end 1472 | elseif (nconv < k) 1473 | if (warnNonConvergence) 1474 | warning('MATLAB:eigs:NotAllEigsConverged', ... 1475 | 'Only %d of the %d requested eigenvalues converged.', ... 1476 | nconv,k) 1477 | else 1478 | flag = 1; 1479 | end 1480 | end 1481 | end 1482 | end % processEUPDinfo 1483 | 1484 | %-------------------------------------------------------------------------% 1485 | function printTimings 1486 | % Print the time taken for each major stage of the EIGS algorithm 1487 | if (mode == 1) 1488 | innerstr = sprintf(['Compute A*X:' ... 1489 | ' %f\n'],cputms(3)); 1490 | elseif (mode == 3) 1491 | if isempty(B) 1492 | innerstr = sprintf(['Solve (A-SIGMA*I)*X=Y for X:' ... 1493 | ' %f\n'],cputms(3)); 1494 | else 1495 | innerstr = sprintf(['Solve (A-SIGMA*B)*X=B*Y for X:' ... 1496 | ' %f\n'],cputms(3)); 1497 | end 1498 | end 1499 | if ((mode == 3) && (Amatrix)) 1500 | if isempty(B) 1501 | prepstr = sprintf(['Pre-processing, including lu(A-sigma*I):' ... 1502 | ' %f\n'],cputms(1)); 1503 | else 1504 | prepstr = sprintf(['Pre-processing, including lu(A-sigma*B):' ... 1505 | ' %f\n'],cputms(1)); 1506 | end 1507 | else 1508 | prepstr = sprintf(['Pre-processing:' ... 1509 | ' %f\n'],cputms(1)); 1510 | end 1511 | sstr = sprintf('***********CPU Timing Results in seconds***********'); 1512 | ds = sprintf(['\n' sstr '\n' ... 1513 | prepstr ... 1514 | 'ARPACK''s %s: %f\n' ... 1515 | innerstr ... 1516 | 'Post-processing with ARPACK''s %s: %f\n' ... 1517 | '***************************************************\n' ... 1518 | 'Total: %f\n' ... 1519 | sstr '\n'], ... 1520 | aupdfun,cputms(2),eupdfun,cputms(4),cputms(5)); 1521 | disp(ds) 1522 | end % printTimings 1523 | 1524 | %-------------------------------------------------------------------------% 1525 | % End of nested functions 1526 | %-------------------------------------------------------------------------% 1527 | 1528 | end % EIGS 1529 | 1530 | %-------------------------------------------------------------------------% 1531 | % Subfunctions 1532 | %-------------------------------------------------------------------------% 1533 | function tf = ishermitian(A) 1534 | %ISHERMITIAN 1535 | tf = isequal(A,A'); 1536 | end % ishermititan 1537 | 1538 | function BisHpd = checkTridiagForHSD(alpha, beta) 1539 | % CHECKTRIDIAGFORHSD 1540 | % Uses Sturm sequence on alpha (diagonal) and beta (superdiagonal) to 1541 | % determine if the matrix diag(alpha,0) + diag(beta,1) + diag(beta,-1) is 1542 | % Positive Semi-definite. 1543 | n = length(alpha); 1544 | BisHpd = true; 1545 | d = alpha(1); 1546 | if d < 0 1547 | BisHpd = false; 1548 | return; 1549 | end 1550 | for k = 1:(n-1) 1551 | if d == 0 1552 | d = eps*(abs(beta(k))+eps); 1553 | end 1554 | d = alpha(k+1) - beta(k)*(beta(k)/d); 1555 | if d < 0 1556 | BisHpd = false; 1557 | return; 1558 | end 1559 | end 1560 | end % checkTridiagForHSD 1561 | %-------------------------------------------------------------------------% 1562 | % End of subfunctions 1563 | %-------------------------------------------------------------------------% 1564 | --------------------------------------------------------------------------------