function c = conv2( a, b, shape )
%
%   c = conv2( a, b ) - performs 2D convolution of matrices a and b
%
%                     - if [ma,na] = size(a) and [mb,nb] = size(b), then
%                       size(c) = [ma+mb-1, na+nb-1]
%
%   c = conv2( a, b, shape ) - returns subsection of 2D convolution with
%                       size specified by shape
%
%           'full'      - (defalut) returns full 2D convolution
%           'same'      - returns central part that is same size as a
%           'valid'     - returns only those parts of the convolution that are
%                         computed without the zero-padded edges
%
%   note: conv2 is most efficient when size(a) > size(b)
%

    % check arguements
    if ( nargin != 2 && nargin != 3 )
        error( "conv2 requires 2 or 3 arguements" );
    endif
    
    % get array sizes
    [ma, na] = size(a);
    [mb, nb] = size(b);
    
    
    % do full convolution
    c = zeros( ma+mb-1, na+nb-1 );
    for i = 1:mb
        for j = 1:nb
            r1 = i;
            r2 = r1 + ma - 1;
            c1 = j;
            c2 = c1 + na - 1;
            c(r1:r2,c1:c2) = c(r1:r2,c1:c2) + b(i,j) * a;
        endfor
    endfor
    
    if ( nargin == 2 || strcmp(shape, 'full') )
        % nothing to do, full convolution done
    elseif ( strcmp(shape, 'same') )
        % extract region of size(a) from c
        r1 = floor(mb/2) + 1;
        r2 = r1 + ma - 1;
        c1 = floor(nb/2) + 1;
        c2 = c1 + na - 1;
        c = c(r1:r2, c1:c2);
    elseif ( strcmp(shape, 'valid')  )
        % extract valid region from c
        c = c(mb:ma, nb:na);
    else
        error( "conv2 third arguement must be 'full', 'same', or 'valid'" );
    endif

endfunction
