summaryrefslogtreecommitdiffstats
path: root/SD-VBS/common/toolbox/toolbox_basic/common/ncut.m
blob: 81fb52f3ef85e4d29927f213aaf138748d77f134 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
% function [v,s,na,d] = ncut(a,nv,sigma,offset) 
% Input:
%    a = affinity matrix, hermitian, could be 3D, or a cell
%    nv = number of eigenvectors v
%    sigma = refer to EIGS.M, 0 for smallest, default = 'LR'
%    offset = vector, each for an affinity matrix, offset for nondirectional repulsion
%       W = A - R = (A + offset) - (R + offset)
%       Expected value = offset in affinity value * # of neighboors
% Output:
%    v = generalized eigenvectors of A and D
%    s = eigenvalues
%    na = normalized affinity matrix
%    d = normalization matrix 1/sqrt(rowsum(a))
% This version now accepts multiple weight matrices
% the format of cells are good for sparse affinity matrices

% Jianbo Shi

function [v,s,na,d] = ncut(a,nv,sigma,offset)

is_cell = iscell(a);
if is_cell,
   nw = length(a);
   [nr,nc] = size(a{1});
else
   [nr,nc,nw] = size(a);
end

if nargin<2 | isempty(nv),
   nv = min(nr,6);
end

if nargin<3 | isempty(sigma),
   sigma = 'LR';
end

if nargin<4 | isempty(offset),
   offset = 0;
end;
offset=offset(:);
j = length(offset);
offset(j+1:nw) = offset(j);

d = 0;
na = sparse(nr,nc);
for j=1:nw, % simultaneous partitioning with multiple weight matrices.
   if is_cell,
      w = a{j};
   elseif issparse(a), % only supports 2D indexing
      w = a;
   else
      w = a(:,:,j);
   end
   if j==nw, % to save space
       clear a;
   end
   
   d = d + sum(abs(w),2) + 2*offset(j); % single equivalent D
   
   % modify matrix a to deal with nondirectional repulsion 
   wr = real(w);
   wr = (sum(abs(wr),2)-sum(wr,2))*0.5 + offset(j);
   w = w + spdiags(wr,0,nr,nr);
   
   na = na + w; % single equivalent A
   
   % if you want the rectified individual weight matrix
   %if is_cell,
   %   a{j} = w;      
   %else
   %   a(:,:,j) = w;
   %end
end
clear w wr

% normalize
d = 1./sqrt(d+eps);
if 1,
    na = spmtimesd(na,d,d);    
else    
    d = spdiags(d,0,nr,nr);
    na = d * na * d;
end

options.disp = 0; 
%options.tol = 1e-10;
%options.maxit = 15;

warning off
[v,s] = eigs(na,nv,sigma,options);
s = real(diag(s));
warning on

% to make sure positive eigs always come first
% [x,y] = sort(-s); 
% s = -x;
% v = v(:,y);

% project back to get the eigenvectors for the pair (a,d)
% a x = lambda d x
% na y = lambda y
% x = d^(-1/2) y

if 1,
    v = spdiags(d,0,nr,nr) * v;
else
    v = d * v;
end