Rearrange array into a form suitable for NN training - matlab

I am working on a large dataset that I need to convert to a specific format for further processing. I am looking for advice in this regard.
Sample input:
A = [0.99 -0.99
1 -1
0.55 -0.55]
Sample output:
val(:,:,1,1)=0.99
val(:,:,2,1)=-0.99
val(:,:,1,2)=1
val(:,:,2,2)=-1
val(:,:,1,3)=0.55
val(:,:,2,3)=-0.55
While working on this, I found a code inside the CNN toolbox of MATLAB R2018b
function dummifiedOut = dummify(categoricalIn)
% iDummify Convert a categorical input into a dummified output.
%
% dummifiedOut(1,1,i,j)=1 if observation j is in class i, and zero
% otherwise. Therefore, dummifiedOut will be of size [1, 1, K, N],
% where K is the number of categories and N is the number of
% observation in categoricalIn.
% Copyright 2015-2016 The MathWorks, Inc.
numObservations = numel(categoricalIn);
numCategories = numel(categories(categoricalIn));
dummifiedSize = [1, 1, numCategories, numObservations];
dummifiedOut = zeros(dummifiedSize);
categoricalIn = iMakeHorizontal( categoricalIn );
idx = sub2ind(dummifiedSize(3:4), int32(categoricalIn), 1:numObservations);
dummifiedOut(idx) = 1;
end
function vec = iMakeHorizontal( vec )
vec = reshape( vec, 1, numel( vec ) );
end
Can we modify this block of code in such a way to produce the sample output?

Either do what rinkert suggested, or just use permute directly:
>> val = permute(A, [4,3,2,1])
val(:,:,1,1) =
0.9900
val(:,:,2,1) =
-0.9900
val(:,:,1,2) =
1
val(:,:,2,2) =
-1
val(:,:,1,3) =
0.5500
val(:,:,2,3) =
-0.5500
Note that the function which you posted requires categorical data, whereas you have a simple double array. If you insist on "adapting" the existing dummify, you could do:
function dummifiedOut = dummify(categoricalIn)
dummifiedOut = zeros([1,1,size(categoricalIn)]);
dummifiedOut(:) = categoricalIn;
end
(...although, IMHO, this makes little sense.)

Related

MATLAB to Scilab conversion: mfile2sci error "File contains no instruction"

I am very new to Scilab, but so far have not been able to find an answer (either here or via google) to my question. I'm sure it's a simple solution, but I'm at a loss. I have a lot of MATLAB scripts I wrote in grad school, but now that I'm out of school, I no longer have access to MATLAB (and can't justify the cost). Scilab looked like the best open alternative. I'm trying to convert my .m files to Scilab compatible versions using mfile2sci, but when running the mfile2sci GUI, I get the error/message shown below. Attached is the original code from the M-file, in case it's relevant.
I Searched Stack Overflow and companion sites, Google, Scilab documentation.
The M-file code follows (it's a super basic MATLAB script as part of an old homework question -- I chose it as it's the shortest, most straightforward M-file I had):
Mmax = 15;
N = 20;
T = 2000;
%define upper limit for sparsity of signal
smax = 15;
mNE = zeros(smax,Mmax);
mESR= zeros(smax,Mmax);
for M = 1:Mmax
aNormErr = zeros(smax,1);
aSz = zeros(smax,1);
ESR = zeros(smax,1);
for s=1:smax % for-loop to loop script smax times
normErr = zeros(1,T);
vESR = zeros(1,T);
sz = zeros(1,T);
for t=1:T %for-loop to carry out 2000 trials per s-value
esr = 0;
A = randn(M,N); % generate random MxN matrix
[M,N] = size(A);
An = zeros(M,N); % initialize normalized matrix
for h = 1:size(A,2) % normalize columns of matrix A
V = A(:,h)/norm(A(:,h));
An(:,h) = V;
end
A = An; % replace A with its column-normalized counterpart
c = randperm(N,s); % create random support vector with s entries
x = zeros(N,1); % initialize vector x
for i = 1:size(c,2)
val = (10-1)*rand + 1;% generate interval [1,10]
neg = mod(randi(10),2); % include [-10,-1]
if neg~=0
val = -1*val;
end
x(c(i)) = val; %replace c(i)th value of x with the nonzero value
end
y = A*x; % generate measurement vector (y)
R = y;
S = []; % initialize array to store selected columns of A
indx = []; % vector to store indices of selected columns
coeff = zeros(1,s); % vector to store coefficients of approx.
stop = 10; % init. stop condition
in = 0; % index variable
esr = 0;
xhat = zeros(N,1); % intialize estimated x signal
while (stop>0.5 && size(S,2)<smax)
%MAX = abs(A(:,1)'*R);
maxV = zeros(1,N);
for i = 1:size(A,2)
maxV(i) = abs(A(:,i)'*R);
end
in = find(maxV == max(maxV));
indx = [indx in];
S = [S A(:,in)];
coeff = [coeff R'*S(:,size(S,2))]; % update coefficient vector
for w=1:size(S,2)
r = y - ((R'*S(:,w))*S(:,w)); % update residuals
if norm(r)<norm(R)
index = w;
end
R = r;
stop = norm(R); % update stop condition
end
for j=1:size(S,2) % place coefficients into xhat at correct indices
xhat(indx(j))=coeff(j);
end
nE = norm(x-xhat)/norm(x); % calculate normalized error for this estimate
%esr = 0;
indx = sort(indx);
c = sort(c);
if isequal(indx,c)
esr = esr+1;
end
end
vESR(t) = esr;
sz(t) = size(S,2);
normErr(t) = nE;
end
%avsz = sum(sz)/T;
aSz(s) = sum(sz)/T;
%aESR = sum(vESR)/T;
ESR(s) = sum(vESR)/T;
%avnormErr = sum(normErr)/T; % produce average normalized error for these run
aNormErr(s) = sum(normErr)/T; % add new avnormErr to vector of all av norm errors
end
% just put this here to view the vector
mNE(:,M) = aNormErr;
mESR(:,M) = ESR;
% had an 'end' placed here, might've been unmatched
mNE%reshape(mNE,[],Mmax)
mESR%reshape(mESR,[],Mmax)]
figure
dimx = [1 Mmax];
dimy = [1 smax];
imagesc(dimx,dimy,mESR)
colormap gray
strESR = sprintf('Average ESR, N=%d',N);
title(strESR);
xlabel('M');
ylabel('s');
strNE = sprintf('Average Normed Error, N=%d',N);
figure
imagesc(dimx,dimy,mNE)
colormap gray
title(strNE)
xlabel('M');
ylabel('s');
The command used (and results) follow:
--> mfile2sci
ans =
[]
****** Beginning of mfile2sci() session ******
File to convert: C:/Users/User/Downloads/WTF_new.m
Result file path: C:/Users/User/DOWNLO~1/
Recursive mode: OFF
Only double values used in M-file: NO
Verbose mode: 3
Generate formatted code: NO
M-file reading...
M-file reading: Done
Syntax modification...
Syntax modification: Done
File contains no instruction, no translation made...
****** End of mfile2sci() session ******
To convert the foo.m file one has to enter
mfile2sci <path>/foo.m
where stands for the path of the directoty where foo.m is. The result is written in /foo.sci
Remove the ```` at the begining of each line, the conversion will proceed normally ?. However, don't expect to obtain a working .sci file as the m2sci converter is (to me) still an experimental tool !

Storing Results from multiple loops and creating a data frame looking object in Matlab

i used for loops :
for i=1:length(thetas)
theta = thetas(i); % Utility function
for j=1:length(rhos)
rho = rhos(j);
for ii=1:length(gammas)
gamma = gammas(ii);
[kss]=equilibirum(debt)wherein
end
end
end
where in each step I essentially change some parameter values to get different values for the column vector kss (size: 10000x1)
e.g the vector of parameters I am looping over are:
thetas = [1, 1.5];
rhos = [0, 0.99, 2];
gammas = [-1,0,0.76, 0.9, 1] ;
I want to remember (or store) for which combination of parameters i get the values for `kss'.
How can I do this Matlab in some easy to understand and easy to export (e.g. in Excel) way? An ideal solution, will make my result look like a data frame object as in python(pandas) or R
You can use tables in MATLAB to describe what you wish to accomplish.
kss_table = table;
counter = 1;
for i=1:length(thetas)
theta = thetas(i); % Utility function
for j=1:length(rhos)
rho = rhos(j);
for ii=1:length(gammas)
gamma = gammas(ii);
kss = equilibirum(debt)wherein
kss_table.Theta(counter) = theta;
kss_table.Rho(counter) = rho;
kss_table.Gamma(counter) = gamma;
counter = counter + 1;
end
end
end

How to get a 3D-matrix or cell array efficiently by using vectorized code?

Here is what I want, a 3-D matrix:
K = 2:2.5:10;
den = zeros(1,4,4);
for i = 1:1:4
den(:,:,i) = [1, 5, K(i)-6, K(i)];
end
Or, a cell array is also acceptable:
K = 2:2.5:10;
for i = 1:1:4
den{i} = [1, 5, K(i)-6, K(i)];
end
But I want to know if there is a more efficient way of doing this using vectorized code like:
K = 2:2.5:10;
den = [1, 5, K-6, K];
I know the last code will not get what I wanted. But, like I can use:
v = [1 2 3];
v2 = v.^2;
instead of:
v = [1 2 3];
for i = 1:length(v)
v(i) = v(i)^2;
end
to get the matrix I want. Is there a similar way of doing this so that I can get the 3-D matrix or cell array I mentioned at the beginning more efficiently?
You need to "broadcast" the scalar values in columns so they are of the same length as your K vector. MATLAB does not do this broadcasting automatically, so you need to repeat the scalars and create vectors of the appropriate size. You can use repmat() for this.
K = 2:2.5:10;
%% // transpose K to a column vector:
K = transpose(K);
%% // helper function that calls repmat:
f = #(v) repmat(v, length(K), 1);
%% // your matrix:
den = [f(1) f(5) K-6 K];
This should be more optimized for speed but requires a bit more intermediary memory than the loop does.
Just use reshape with a 1*3 size:
den = reshape([ones(1,length(K));ones(1,length(K))*5; K-6; K],[1 4 length(K)]);
I think the used extra memory by reshape should be low and constant (dependent only on the length of the vector of new sizes).
You can use the classic line equation y=a*x+b, extended to the matrix form:
k = 2:2.5:10 ;
fa = [0 0 1 1].' ; %' // "a" coefficients
fb = [1 5 -6 0].' ; %' // "b" coefficients
d(1,:,:) = fa*k + fb*ones(1,4) ;
The above is better for clarity, but if you're not bothered you can also pack everything in one line:
d(1,:,:) = [0 0 1 1].' * (2:2.5:10) + [1 5 -6 0].' * ones(1,4) ;
If you need to re-use the principle for many different values of k, then you can use an anonymous function to help:
fden = #(k) [0 0 1 1].' * k + [1 5 -6 0].' * ones(1,4) ; %// define anonymous function
k = 2:2.5:10 ;
d(1,:,:) = fden(k) ; %// use it for any value of "k"

change filter(B,A, X) in matlab and Out of memoy Error

this post is related to my previous question : image processing in matlab
as I have uploaded my algorithme there.
the think is that I am trying to change the filtering part of the code.
in matlab filter.m function can accpet filter(B, A, my pixels evolutions in Time) and it return me the filtered values.
but at the moment I have to pass the the whole time series together.
but the problem is that now I want to change the code in a way instead of passing the whole timeseries into the filter, I want to pass one value at a time, but I want filter function treat the value like the nth value not the first valu.
I have created a sudo code, as I am injecting one picture into the code, but I dont know how can change the filtering part., any body has any idea??
clear all
j=1;
for i=0:3000
str = num2str(i);
str1 = strcat(str,'.mat');
load(str1);
D{j}=A(20:200,130:230);
j=j+1;
end
N=5;
w = [0.00000002 0.05;0.05 0.1;0.1 0.15;0.15 0.20;
0.20 0.25;0.25 0.30;0.30 0.35;0.35 0.40;
0.40 0.45;0.45 0.50;0.50 0.55;0.55 0.60;
0.60 0.65;0.65 0.70;0.70 0.75;0.75 0.80;
0.80 0.85;0.85 0.90;0.90 0.95;0.95 0.99999999];
for ind=1:20
wn = w(ind,:);
[b,a] = butter(N,wn);
bCoeff(ind,:)=b;
aCoeff(ind,:)=a;
end
ts=[];
sumLastImages=[];
for k=1:10 %number of images
for bands=1:20 %number of bands
for i=1:10 %image h
for j=1:10 %image w
pixelValue = D{k}(i,j);
% reflectivity elimination
% for the current pixel, have the summation of the same position from before
% images and create a mean value base on the temporal values
sumLastImages(i,j)=pixelValue+sumLastImages(i,j);
meanValue = sumLastImages(i,j)/k;
if(meanValue==0)
filteredimages{bands}(i,j)=0;
continue;
else
pixel_calculated_meanvalue = pixelValue/meanValue;
end
% filter part that need to be changed, and because we are adding
% one value then the reutrn of the filter is one too
ts_f = filter(bCoeff(bands,:), aCoeff(bands,:), ...
pixel_calculated_meanvalue);
filteredimages{bands}(i,j)=ts_f;
end
end
finalImagesSummation{bands}(:,:) = ...
(filteredimages{bands}(:,:)^2)+finalImagesSummation{bands}(:,:);
finalImages{bands}(:,:)=finalImagesSummation/k;
end
end
EDIT
I managed to change the code like this, which now I load the fist 200 images, and after that I am able to inject the images one by one into the filter, but now the problem is that I am getting "Out of memory. Type HELP MEMORY for your options." error for big
images.
here is my code any idea to efficent the code :
%%
cd('D:\MatlabTest\06-06-Lentils');
clear all
%%
N=5;
W = [0.0 0.10;0.10 0.20;0.20 0.30;0.30 0.40;
0.40 0.50;0.50 0.60 ;0.60 0.70;0.70 0.80 ;
0.80 0.90;0.90 1.0];
[bCoeff{1},aCoeff{1}] = butter(N,0.1,'Low');
for ind=2:9
wn = W(ind,:);
[b,a] = butter(N,wn);
bCoeff{ind}=b;
aCoeff{ind}=a;
end
[bCoeff{10},aCoeff{10}] = butter(N,0.9,'high');
%%
j=1;
D = zeros(200,380,320);
T = 200;
K = 0:399;
l = T+1;
Yout = cell(1,10);
figure;
for i = 1:length(K)-200
disp(i)
if i == 1
for j = 1:T
str = int2str(K(1)+j-1);
str1 = strcat(str,'.mat');
load(str1);
D(j,1:380,1:320) = A;
end
else
str = int2str(l);
str1 = strcat(str,'.mat');
load(str1);
temp = D(2:200,1:380,1:320) ;
temp(200,1:380,1:320) = A;
D = temp;
clear temp
l = l +1;
end
for p = 1:380
for q = 1:320
x = D(:,p,q) - mean(D(:,p,q));
for k = 1:10
temp = filter(bCoeff{k},aCoeff{k},x);
if i == 1
Yout{k}(p,q) = mean(temp);
else
Yout{k}(p,q) = (Yout{k}(p,q) + mean(temp))/2;
end
end
end
end
for k = 1:10
subplot(5,2,k)
subimage(Yout{k}*1000,[0 255]);
color bar
colormap jet
end
pause(0.01);
end
disp('Done Loading...')
No need to rewrite the filter function, there is a simple solution!
If you want to feed filter with one sample at a time, you need to pass the state parameters as well so that each input sample is processed depending on its predecessor. After filtering, the new state is actually returned as a second parameter, so that most of the work is already done by MATLAB for you. This is good news!
For the sake of readability, allow me to temporarily replace your variable names with simple letters:
a = aCoeff(bands, :);
b = bCoeff(bands, :);
x = pixel_calculated_meanvalue;
ts_f is represented by y.
And so, this:
y = filter(b, a, x);
is actually equivalent to this:
N = numel(x);
y = zeros(N, 1); %# Preallocate memory for output
z = zeros(max(length(a), length(b)) - 1, 1); %# This is the initial filter state
for i = 1:N
[y(i), z] = filter(b, a, x(i), z);
end
You can check for yourself that the result is the same!
For your example, the code would be:
N = numel(pixel_calculated_meanvalue);
ts_f = zeros(N, 1);
z = zeros(max(length(aCoeff(bands, :)), length(bCoeff(bands, :))) - 1, 1);
for i = 1:N
[ts_f(i), z] = filter(bCoeff(bands, :), aCoeff(bands, :), ...
pixel_calculated_meanvalue(i), z);
end
With this method you can process one input sample at a time, just make sure you store the last filter state after every filter call. If you plan on using multiple filters, you'll have to store a state vector per filter!
Overview
If all you want to have is an IIR filter, which you can feed incrementally, i.e. where you do not have to supply the full vector at once, you can simply implement your own function and use either persistent variables.
Simple approach
The code snippet below defines a function myFilter, which makes use of persistent
variables, which you can control with the following commands:
init: set up the IIR coefficients
getA: returns the A coefficients, i.e. the outputweights
getB: returns the B coefficients, i.e. the input weights
getX: returns the stored input data x[0], x[1], ... x[M]
getY: returns the output data y[0], y[1], ... y[N]
getCurrentY: returns the last output data y[N]
Here is the function:
function result = myFilter(varargin)
% myFilter A simple IIR filter which can be fed incrementally.
%
% The filter is controlled with the following commands:
% myFilter('init', B, A)
% Initializes the coefficients B and A. B are the weights for the
% input and A for the output.
% myFilter('reset')
% Resets the input and output buffers to zero.
% A = myFilter('getA')
% B = myFilter('getB')
% Returns the filter coefficients A and B, respectively.
% x = myFilter('getX')
% y = myFilter('getY')
% Returns the buffered input and output vectors.
% y = myFilter('getCurrentY')
% Returns the current output value.
% myFilter(x)
% Adds the new value x as input to the filter and updates the
% output.
persistent Bcoeff
persistent Acoeff
persistent x
persistent y
if ischar(varargin{1})
% This is a command.
switch varargin{1}
case 'init'
Bcoeff = varargin{2};
Acoeff = varargin{3};
Bcoeff = Bcoeff / Acoeff(1);
Acoeff = Acoeff / Acoeff(1);
x = zeros(size(Bcoeff));
y = zeros(1, length(Acoeff) - 1);
return
case 'reset'
x = zeros(size(Bcoeff));
y = zeros(1, length(Acoeff) - 1);
return
case 'getA'
result = Acoeff;
return
case 'getB'
result = Bcoeff;
return
case 'getX'
result = x;
return
case 'getY'
result = y;
return
case 'getCurrentY'
result = y(1);
return
otherwise
error('Unknown command');
end
end
% A new value has to be filtered.
xnew = varargin{1};
x = [xnew, x(1:end-1)];
ynew = sum(x .* Bcoeff) - sum(y .* Acoeff(2:end));
y = [ynew, y(1:end-1)];
end
And a usage example:
% Define the filter coefficients. Bcoeff acts on the input, Acoeff on
% the output.
Bcoeff = [4, 5];
Acoeff = [1, 2, 3];
% Initialize the filter.
myFilter('init', Bcoeff, Acoeff);
% Add a value to be filtered.
myFilter(10)
myFilter('getCurrentY')
ans =
40
% Add another one.
myFilter(20)
myFilter('getCurrentY')
ans =
50
% And a third one.
myFilter(30)
myFilter('getCurrentY')
ans =
0
% Compare with the Matlab filter function.
filter(Bcoeff, Acoeff, [10 20 30])
ans =
40 50 0
The drawback of this approach is that it is only possible to have one active filter
simultaneously. This is problematic e.g. in your question, where you have different
filters which are updated in an alternating fashion.
Advanced approach
In order to operate multiple filters simultatenously, you need some way to identify
the filter. The solution I present here works with handles. A handle is simple an
integer. To be more precise, it is actually an index into a persistent array, which
itself holds the filter state, i.e. the filter coefficients and the buffers for the
input and the output.
The calling syntax is a bit more complicated, because you have to pass a handle. However,
it is possible that multiple filters are active simultaneously.
function result = myFilterH(varargin)
% myFilterH A simple IIR filter which can be fed incrementally.
% Operates on a filter handle.
%
% The filter is controlled with the following commands:
% handle = myFilterH('create')
% Creates a new filter handle.
% myFilterH(handle, 'init', B, A)
% Initializes the coefficients B and A. B are the weights for the
% input and A for the output. handle identifies the filter.
% myFilterH(handle, 'reset')
% Resets the input and output buffers to zero.
% A = myFilterH(handle, 'getA')
% B = myFilterH(handle 'getB')
% Returns the filter coefficients A and B, respectively.
% x = myFilterH(handle, 'getX')
% y = myFilterH(handle, 'getY')
% Returns the buffered input and output vectors.
% y = myFilterH(handle, 'getCurrentY')
% Returns the current output value.
% myFilterH(handle, x)
% Adds the new value x as input to the filter and updates the
% output.
persistent handles
if ischar(varargin{1})
if strcmp(varargin{1}, 'create')
if isempty(handles)
handles = struct('x', [], 'y', [], 'A', [], 'B', []);
result = 1;
else
result = length(handles) + 1;
handles(result).x = [];
end
return
else
error('First argument must be a filter handle or ''create''');
end
end
% The first input should be the handles(hIdx).
hIdx = varargin{1};
if hIdx < 0 || hIdx > length(handles)
error('Invalid filter handle')
end
if ischar(varargin{2})
% This is a command.
switch varargin{2}
case 'init'
handles(hIdx).B = varargin{3};
handles(hIdx).A = varargin{4};
handles(hIdx).B = handles(hIdx).B / handles(hIdx).A(1);
handles(hIdx).A = handles(hIdx).A / handles(hIdx).A(1);
handles(hIdx).x = zeros(size(handles(hIdx).B));
handles(hIdx).y = zeros(1, length(handles(hIdx).A) - 1);
return
case 'reset'
handles(hIdx).x = zeros(size(handles(hIdx).B));
handles(hIdx).y = zeros(1, length(handles(hIdx).A) - 1);
return
case 'getA'
result = handles(hIdx).A;
return
case 'getB'
result = handles(hIdx).B;
return
case 'getX'
result = handles(hIdx).x;
return
case 'getY'
result = handles(hIdx).y;
return
case 'getCurrentY'
result = handles(hIdx).y(1);
return
otherwise
error('Unknown command');
end
end
% A new value has to be filtered.
xnew = varargin{2};
handles(hIdx).x = [xnew, handles(hIdx).x(1:end-1)];
ynew = sum(handles(hIdx).x .* handles(hIdx).B) ...
- sum(handles(hIdx).y .* handles(hIdx).A(2:end));
handles(hIdx).y = [ynew, handles(hIdx).y(1:end-1)];
end
And the example:
% Define the filter coefficients.
Bcoeff = [4, 5];
Acoeff = [1, 2, 3];
% Create new filter handles.
fh1 = myFilterH('create');
fh2 = myFilterH('create');
% Initialize the filter handle. Note that reversing Acoeff and Bcoeff creates
% two totally different filters.
myFilterH(fh1, 'init', Bcoeff, Acoeff);
myFilterH(fh2, 'init', Acoeff, Bcoeff);
% Add a value to be filtered.
myFilterH(fh1, 10);
myFilterH(fh2, 10);
[myFilterH(fh1, 'getCurrentY'), myFilterH(fh2, 'getCurrentY')]
ans =
40.0000 2.5000
% Add another one.
myFilterH(fh1, 20);
myFilterH(fh2, 20);
[myFilterH(fh1, 'getCurrentY'), myFilterH(fh2, 'getCurrentY')]
ans =
50.0000 6.8750
% And a third one.
myFilterH(fh1, 30);
myFilterH(fh2, 30);
[myFilterH(fh1, 'getCurrentY'), myFilterH(fh2, 'getCurrentY')]
ans =
0 16.4063
% Compare with the Matlab filter function.
filter(Bcoeff, Acoeff, [10 20 30])
ans =
40 50 0
filter(Acoeff, Bcoeff, [10 20 30])
ans =
2.5000 6.8750 16.4063
Using it for your example
To use the advanced approach in your example, you could first create an array of filters:
fh = [];
for ind = 1:20
wn = w(ind,:);
[b,a] = butter(N,wn);
fh(ind) = myFilterH('create');
myFilterH(fh(ind), 'init', b, a);
end
Later on in the filter part simply add your value to all of the filters. However, for this
you also need to reverse the loops because right now you would need one filter per
band per pixel. If you loop over pixels first and then over bands, you can reuse the filters:
for height = 1:10
for width = 1:10
for bands = 1:20
myFilterH(fh(bands), 'reset');
for k = 1:10
[...]
ts_f = myFilterH(fh(bands), ...
pixel_calculated_meanvalue);
filteredimages{bands}(i,j) = myFilterH(fh(bands), 'getCurrentY');
end
end
end
end
Hope that helps!
If I understand the question correctly, the crux is "How do I return multiple things from a Matlab function?"
You can return multiple things like this:
function [a, b, np, x, y] = filter(ord, a, b, np, x, y)
%code of function here
%make some changes to a, b, np, x, and y
end
If you want to call the filter from another function and catch its return values, you can do this:
function [] = main()
%do some stuff, presumably generate initial values for ord, a, b, np, x, y
[new_a, new_b, new_np, new_x, new_y] = filter(ord, a, b, np, x, y)
end
In short, if you do function [x, y] = myfunc(a, b), then myfunc returns both x and y.

Vectorizing sums of different diagonals in a matrix

I want to vectorize the following MATLAB code. I think it must be simple but I'm finding it confusing nevertheless.
r = some constant less than m or n
[m,n] = size(C);
S = zeros(m-r,n-r);
for i=1:m-r+1
for j=1:n-r+1
S(i,j) = sum(diag(C(i:i+r-1,j:j+r-1)));
end
end
The code calculates a table of scores, S, for a dynamic programming algorithm, from another score table, C.
The diagonal summing is to generate scores for individual pieces of the data used to generate C, for all possible pieces (of size r).
Thanks in advance for any answers! Sorry if this one should be obvious...
Note
The built-in conv2 turned out to be faster than convnfft, because my eye(r) is quite small ( 5 <= r <= 20 ). convnfft.m states that r should be > 20 for any benefit to manifest.
If I understand correctly, you're trying to calculate the diagonal sum of every subarray of C, where you have removed the last row and column of C (if you should not remove the row/col, you need to loop to m-r+1, and you need to pass the entire array C to the function in my solution below).
You can do this operation via a convolution, like so:
S = conv2(C(1:end-1,1:end-1),eye(r),'valid');
If C and r are large, you may want to have a look at CONVNFFT from the Matlab File Exchange to speed up calculations.
Based on the idea of JS, and as Jonas pointed out in the comments, this can be done in two lines using IM2COL with some array manipulation:
B = im2col(C, [r r], 'sliding');
S = reshape( sum(B(1:r+1:end,:)), size(C)-r+1 );
Basically B contains the elements of all sliding blocks of size r-by-r over the matrix C. Then we take the elements on the diagonal of each of these blocks B(1:r+1:end,:), compute their sum, and reshape the result to the expected size.
Comparing this to the convolution-based solution by Jonas, this does not perform any matrix multiplication, only indexing...
I would think you might need to rearrange C into a 3D matrix before summing it along one of the dimensions. I'll post with an answer shortly.
EDIT
I didn't manage to find a way to vectorise it cleanly, but I did find the function accumarray, which might be of some help. I'll look at it in more detail when I am home.
EDIT#2
Found a simpler solution by using linear indexing, but this could be memory-intensive.
At C(1,1), the indexes we want to sum are 1+[0, m+1, 2*m+2, 3*m+3, 4*m+4, ... ], or (0:r-1)+(0:m:(r-1)*m)
sum_ind = (0:r-1)+(0:m:(r-1)*m);
create S_offset, an (m-r) by (n-r) by r matrix, such that S_offset(:,:,1) = 0, S_offset(:,:,2) = m+1, S_offset(:,:,3) = 2*m+2, and so on.
S_offset = permute(repmat( sum_ind, [m-r, 1, n-r] ), [1, 3, 2]);
create S_base, a matrix of base array addresses from which the offset will be calculated.
S_base = reshape(1:m*n,[m n]);
S_base = repmat(S_base(1:m-r,1:n-r), [1, 1, r]);
Finally, use S_base+S_offset to address the values of C.
S = sum(C(S_base+S_offset), 3);
You can, of course, use bsxfun and other methods to make it more efficient; here I chose to lay it out for clarity. I have yet to benchmark this to see how it compares with the double-loop method though; I need to head home for dinner first!
Is this what you're looking for? This function adds the diagonals and puts them into a vector similar to how the function 'sum' adds up all of the columns in a matrix and puts them into a vector.
function [diagSum] = diagSumCalc(squareMatrix, LLUR0_ULLR1)
%
% Input: squareMatrix: A square matrix.
% LLUR0_ULLR1: LowerLeft to UpperRight addition = 0
% UpperLeft to LowerRight addition = 1
%
% Output: diagSum: A vector of the sum of the diagnols of the matrix.
%
% Example:
%
% >> squareMatrix = [1 2 3;
% 4 5 6;
% 7 8 9];
%
% >> diagSum = diagSumCalc(squareMatrix, 0);
%
% diagSum =
%
% 1 6 15 14 9
%
% >> diagSum = diagSumCalc(squareMatrix, 1);
%
% diagSum =
%
% 7 12 15 8 3
%
% Written by M. Phillips
% Oct. 16th, 2013
% MIT Open Source Copywrite
% Contact mphillips#hmc.edu fmi.
%
if (nargin < 2)
disp('Error on input. Needs two inputs.');
return;
end
if (LLUR0_ULLR1 ~= 0 && LLUR0_ULLR1~= 1)
disp('Error on input. Only accepts 0 or 1 as input for second condition.');
return;
end
[M, N] = size(squareMatrix);
if (M ~= N)
disp('Error on input. Only accepts a square matrix as input.');
return;
end
diagSum = zeros(1, M+N-1);
if LLUR0_ULLR1 == 1
squareMatrix = rot90(squareMatrix, -1);
end
for i = 1:length(diagSum)
if i <= M
countUp = 1;
countDown = i;
while countDown ~= 0
diagSum(i) = squareMatrix(countUp, countDown) + diagSum(i);
countUp = countUp+1;
countDown = countDown-1;
end
end
if i > M
countUp = i-M+1;
countDown = M;
while countUp ~= M+1
diagSum(i) = squareMatrix(countUp, countDown) + diagSum(i);
countUp = countUp+1;
countDown = countDown-1;
end
end
end
Cheers