Code covered by the BSD License  

Highlights from
Statistical Learning Toolbox

from Statistical Learning Toolbox by Dahua Lin
Functions for statistical learning, pattern recognition and computer vision, covering many topics.

slnbreconweights(X0, X, G, varargin)
function WG = slnbreconweights(X0, X, G, varargin)
%SLNBRECONWEIGHTS Solve the optimal reconstruction weights on given neighbors
%
% $ Syntax $
%   - WG = slnbreconweights(X0, X, G, ...)
%
% $ Arguments $
%   - X0:       The reference samples to reconstruct the query samples
%   - X:        The query samples
%   - G:        The graph giving the neighborhood relations 
%   - WG:       The weighted graph giving the solved weights
%
% $ Description $
%   - WG = slnbreconweights(X0, X, G, ...) solves the optimal weights to
%     reconstruct the samples in X from those in X0. If X is empty, then
%     it would use X0 as X. The graph G indicates the neighborhood 
%     relation, having n0 sources and n targets. The WG is a graph with
%     of the same size as G, and the reconstuction weights are placed
%     in the positions corresponding to those in G. 
%     You can specify the following properties to control the solving:
%     \*
%     \t    Table. The Properties of Reconstruction Weights Solving
%     \h       name        &     description
%            'constraint'  & The constraint on the solution, it can be
%                            one of the following string to indicate a
%                            single constraint or a cell array of multiple
%                            strings to indicate compound constaints.
%                            - 'nonneg':  non-negative
%                            - 's1':      the weights sum to 1
%                            (default = 's1')
%            'delta'       & The value of regularization. In practice, 
%                            regularization is essential to guarantee the
%                            stability of the solution. In implementation,
%                            the diagonal elements of the gram matrix will
%                            be added with a value:
%                               (delta^2) * trace(G) / K
%                            here G is X^T * X, K is the neighbor number.
%                            (default = 0.1)
%            'solver'      & The solver offered by user (function handle).  
%                            If the user specify a non-empty solver, then 
%                            it will use the user's solver to solve 
%                            weights. The solver is like the form:
%                               w = f(X, y)
%                            Here X is d x K neighbor sample matrix, y is
%                            a d x 1 vector representing the target sample.
%                            It should output a K x 1 vector giving the
%                            reconstruction weights. 
%                            By default, solver = [], indicating to use
%                            internal solver based on constraint and delta.   
%            'thres'       & The thres, if the ratio of a weight value
%                            to the average weight for that reconstruction
%                            is lower than thres, the weight is set 
%                            to strictly zeros. This would significantly
%                            reduces the near-zero weights, and thus
%                            reduces the complexity of the graph.
%                            (default = 1e-8)
%     \*
%
% $ Remarks $
%   - When the user specify a non-empty solver, the internal solver will
%     not be used, thus constraint and delta will not take effect.
%
%   - G would be in all acceptable graph form. WG will always be a 
%     numeric matrix. If G is a sparse adjmat, then WG would be sparse,
%     otherwise WG is full.
%
%   - With the WG solved, to reconstruct by weighed combination of
%     neighbors, you can simply write it as: Xr = X0 * WG, then Xr
%     is a d x n matrix with the j-th column reconstructed from the 
%     referenced samples in Xr using the j-th column's weights in WG.
%
% $ History $
%   - Created by Dahua Lin, on Sep 11st, 2006
%

%% parse and verify input arguments

if nargin < 3
    raise_lackinput('slnbreconweights', 3);
end

if ~isnumeric(X0) || ndims(X0) ~= 2
    error('sltoolbox:invalidarg', ...
        'X should be a 2D numeric matrix');
end
[d, n0] = size(X0);


if isempty(X)
    X = X0;    
else
    if ~isnumeric(X) || ndims(X) ~= 2
        error('sltoolbox:invalidarg', ...
            'X0 should be a 2D numeric matrix');
    end        
    if size(X, 1) ~= d
        error('sltoolbox:sizmismatch', ...
            'The sample dimension in X is not the same as that in X0');
    end
end
n = size(X, 2);

gi = slgraphinfo(G);
if gi.n ~= n0 || gi.nt ~= n
    error('sltoolbox:sizmismatch', ...
        'The size of the graph is not consisitent with the sample set');
end

opts.constraint = 's1';
opts.delta = 0.1;
opts.solver = [];
opts.thres = 1e-8;
opts = slparseprops(opts, varargin{:});

thres = opts.thres;

%% Prepare parameters

% prepare graph
if ~strcmp(gi.form, 'adjmat')
    G = sladjmat(G, 'sparse', true, 'valtype', 'logical');
end
    
% prepare solver
if isempty(opts.solver)
       
    % parse constraints
    cs = opts.constraint;
    if ~isempty(cs)
        if ~iscell(cs)
            cs = {cs};
        end
        constraint = parse_constraints(cs);
    else
        constraint = parse_constraints({});
    end
    
    % decide solver
    if ~constraint.nonneg
        delta2 = opts.delta^2;
        if ~constraint.s1
            wsolver = @(X, y) internal_wsolver_unc(X, y, delta2);
        else
            wsolver = @(X, y) internal_wsolver_s1(X, y, delta2);
        end
    else
        optimopts = optimset('Display', 'off', 'LargeScale', 'off');
        if ~constraint.s1
            wsolver = @(X, y) internal_wsolver_nonneg(X, y, opts.delta, optimopts);
        else
            wsolver = @(X, y) internal_wsolver_nonneg_s1(X, y, opts.delta, optimopts);
        end
    end                           
    
else
    if ~isa(opts.solver, 'function_handle')
        error('The weight solver should be a function handle');
    end
    wsolver = opts.solver;
end


%% main skeleton

% init WG
if issparse(G)
    WG = spalloc(n0, n, nnz(G));
else
    WG = zeros(n0, n);
end

% solve weights
for i = 1 : n
    nbinds = find(G(:,i));
    if ~isempty(nbinds)        
        Xnb = X0(:, nbinds);
        y = X(:,i);
        w = wsolver(Xnb, y);
        if thres > 0
            absw = abs(w);
            curthres = thres * sum(absw) / length(w);
            w(absw < curthres) = 0;
        end        
        WG(nbinds, i) = w;
    end    
end


%% constraint parsing function

function c = parse_constraints(cs)

ncs = length(cs);

c = struct('nonneg', false, 's1', false);

for i = 1 : ncs
    cname = cs{i};
    if ~ischar(cname)
        error('sltoolbox:invalidarg', ...
            'The constraint should be given in char string');
    end
    switch cname
        case 'nonneg'
            c.nonneg = true;
        case 's1'
            c.s1 = true;
        otherwise
            error('sltoolbox:invalidarg', ...
                'Invalid constraint name for weight solving: %s', cname);
    end
end



%% The internal weight solvers

% unconstrained solver
function w = internal_wsolver_unc(X, y, delta2)

[G, Xty] = compute_G_Xty(X, y, delta2);
w = G \ Xty; 

% solver with s1 constraint
function w = internal_wsolver_s1(X, y, delta2)

[G, Xty, K] = compute_G_Xty(X, y, delta2);
wu = G \ [Xty, ones(K, 1)];

w = wu(:,1);
u = wu(:,2);
lambda = (1 - sum(w)) / sum(u);
w = w + lambda * u;

% solver with nonnegative constraint
function w = internal_wsolver_nonneg(X, y, delta, optimopts)

[Xa, ya, K] = augformulate(X, y, delta);
if K <= 20
    w = lsqnonneg(Xa, ya, [], optimopts);
else
    lb = zeros(K, 1);
    w = lsqlin(Xa, ya, [], [], [], [], lb, [], [], optimopts);
end

% solver with nonnegative and s1 constraint
function w = internal_wsolver_nonneg_s1(X, y, delta, optimopts)

[Xa, ya, K] = augformulate(X, y, delta);

Aeq = ones(1, K);
beq = 1;
lb = zeros(K, 1);
w = lsqlin(Xa, ya, [], [], Aeq, beq, lb, [], [], optimopts);


% solver preparation function

function [G, Xty, K] = compute_G_Xty(X, y, delta2)

% compute Xt, G, and Xty
K = size(X, 2);
Xt = X';
G = Xt * X;
Xty = Xt * y;

% regularize
if delta2 > 0
    diaginds = (1:K)*(K+1) - K;
    rv = delta2 * sum(G(diaginds)) / K;
    G(diaginds) = G(diaginds) + rv;
end

function [Xa, ya, K] = augformulate(X, y, delta)

K = size(X, 2);
if delta ~= 0
    Xa = [X; delta * eye(K)];
    ya = [y; zeros(K, 1)];
else
    Xa = X;
    ya = y;
end

Contact us at files@mathworks.com