Code covered by the BSD License  

Highlights from
Sparse sub access

Sparse sub access

by

 

30 Mar 2009 (Updated )

This package allows to retrieve and assign values of sparse matrix in one shot.

spsubsasgn(varargin)
function S = spsubsasgn(varargin)
% function S = SPSUBSASGN(S, r, c, v)
%
% PURPOSE: a new sparse matrix after assigning S(r(:), c(:)) = v(:)
%
% SPSUBSASGN(..., fun)
%   where fun is a function handle: apply two-variates FUN before assign
%       the values S(k) = fun(S(k),v(k)), (k is corresponding linear-index)
%    Reverse order of input variables SPSUBSASGN(r, c, v, S, fun) to
%    apply function in other way around: S(k) = fun(v(k),S(k))
%
% FUN can either be a function handle in mfile or following functions:
%
%     @asgn           Assign value
%     @plus           Plus
%     @minus          Minus
%     @times          Array multiply
%     @rdivide        Right array divide
%     @ldivide        Left array divide
%     @power          Array power
%     @max            Binary maximum
%     @min            Binary minimum
%     @rem            Remainder after division
%     @mod            Modulus after division
%     @atan2	        Four-quadrant inverse tangent
%     @hypot	        Square root of sum of squares
%     @eq             Equal
%     @ne             Not equal
%     @lt             Less than
%     @le             Less than or equal
%     @gt             Greater than
%     @ge             Greater than or equal
%     @and            Element-wise logical AND
%     @or             Element-wise logical OR
%     @xor            Logical EXCLUSIVE OR
%
% Note: This function is useful for sparse because sometime a straight
% forward linear-indexing might not work for large indexes (overflow)
%
% Author Bruno Luong <brunoluong@yahoo.com>
% Last update: 15/April/2009
%   18/August/2009 tolerate setting UINT8/INT8 to Logical sparse
%   13-Nov-2010 expand scalar row and column

persistent MEXFLAG

if nargin<4
    error('SPSUBSASGN requires at least four inputs');
else
    if issparse(varargin{4})
        swapops = true;
        [r c v S] = deal(varargin{1:4});
    else
        swapops = false;
        [S r c v] = deal(varargin{1:4});
    end
end

if nargin>=5
    fun=varargin{5};
else
    fun=[];
end

assignflag = (isempty(fun) || isasgn(fun));

if ~issparse(S) || ~isnumeric(r) || ~isnumeric(r)
    error('S must be sparse matrix and r and c must be valid subindexes');
end

if any(r(:)<1) || (any(r(:)>size(S,1)) && ~assignflag)
    error('Row subscript out of range')
end

if any(c(:)<1) || (any(c(:)>size(S,2)) && ~assignflag)
    error('Column subscript out of range')
end

if ndims(r) ~= ndims(c)
    error('r and c must have a same dimension')
else
    % expand row to match size of column
    if isscalar(r)
        r = repmat(r,size(c));
    elseif isscalar(c)
        % expand column to match size of row
        c = repmat(c,size(r));
    elseif isvector(r) && isvector(c) && (size(r,1)>1 || size(c,1)>1)
        % If one of them is row vector, reshape it column vector
        % for compatible
        r = reshape(r, [], 1);
        c = reshape(c, [], 1);
    elseif ~all(size(r)==size(c))
        error('r and c must have a same dimension')
    end
end

if isscalar(v)
    v = repmat(v,size(r));
end

% Check if mex-file getspvalmex exists
if nargin>=6
    MEXFLAG = varargin{6};
end

if isempty(MEXFLAG)
    MEXFLAG = ~isempty(strfind(which('setspvalmex'),mexext));
    if ~MEXFLAG
        warning('Mex has not built. Recommendation > mex -v -O setspvalmex.c');
    end
end

% Basic assign value
if assignflag
    tref = spcalib();
    if tref.factory
        warning('Calibration not yet performed. Recommendation > spcalib(''auto'')');
    end
    tmex = tref.tsetval*numel(v)*max(log2(nnz(S)),7);
    tadd = tref.tgetval*(numel(v)*max(log2(nnz(S)),7))+tref.tadd*(nnz(S)+numel(v));
    if MEXFLAG && (tmex<tadd)
        % Cast to the same class
        if ~strcmp(class(v),class(S))
            if islogical(S) && ~any(strcmp(class(v),{'uint8' 'int8'}))
                v = feval(class(S),v);
            end
        end
        S = setspvalmex(S, r(:), c(:), v(:));
    else % This is now slower
        sk = spsubsref(S, r(:), c(:));
        v(:) = v(:) - sk;
        S = S + sparse(r(:), c(:), v(:), size(S,1), size(S,2));
    end
else
    % Addition
    if isequal(fun,@plus)
        S = S + sparse(r(:), c(:), v(:), size(S,1), size(S,2));
    elseif isequal(fun,@minus) && ~swapops % Substraction in something to S
        S = S - sparse(r(:), c(:), v(:), size(S,1), size(S,2));
    else % Other cases
        sk = spsubsref(S, r(:), c(:));
        if swapops
            [arg1 arg2] = deal(v(:), sk);
        else
            [arg1 arg2] = deal(sk, v(:));
        end
        v(:) = feval(fun, arg1, arg2);
        S = setspvalmex(S, r(:), c(:), v(:));
    end
end

end % spsubsasgn

% Make sure the function handle is the right local @asgn
function b = isasgn(fun)
if isequal(fun,@asgn)
    info=functions(fun);
    funpath=fileparts(info.file);
    thispath=fileparts(mfilename('fullpath'));
    b=strcmp(funpath,thispath);
else
    b = false;
end
end

Contact us