How do you find an 'M' by 'M' submatrix in the center of an input 'N' by 'N' matrix? (In Matlab) - matlab

How do I write a function in Matlab to output the M x M submatrix at the center of an N x N input matrix? The function should have two input arguments—the N x N input matrix (2D array) and the size of the square submatrix, M, to be extracted from the input matrix. The sole output should be the M x M submatrix at the center of the input matrix. The function should use for loops to extract the submatrix and not use colon notation or any built-in functions for this part of the code. The function should work for any square input matrix where N ≥ 3. If N is even, M should be even. If N is odd, M should be odd.
Here is a picture of my flowchart so far.

Using For-Loops and Offsetting Indexing
Preface:
Here I like to visualize this question as trimming the matrix. The amount to trim I denote in this example is Trim_Amount. The Trim_Amount dictates the size of the sub-matrix and the start point to begin reading/saving the sub-matrix.
Since the trim amount is always taken from each side you can expect the sub-matrix to have dimensions in the form:
Sub-Matrix Width = M - (2 × Trim_Amount)
2 × Trim_Amount will always result in an even number therefore the following can be said:
if M is even → M - (Even Number) → Even Number
if M is odd → M - (Even Number) → Odd Number
Test Output Results:
I recommend going through the code to filter through any unexpected issues.
Full Script:
Dimension = 7;
Matrix = round(100*rand(Dimension));
Trim_Amount = 1;
[Sub_Matrix] = Grab_Sub_Matrix(Matrix,Trim_Amount);
Matrix
Sub_Matrix
%Function definition%
function [Sub_Matrix] = Grab_Sub_Matrix(Matrix,Trim_Amount)
%Minimum of M must be 5 since N >= 3%
[M,~] = size(Matrix);
%Ensuring the trimming factor does not go over possible range%
Max_Trimming_Factor = M - 3;
if(Trim_Amount > Max_Trimming_Factor)
Trim_Amount = Max_Trimming_Factor;
end
%Fill in the boundaries%
Row_Start_Limit = Trim_Amount + 1;
Column_Start_Limit = Trim_Amount + 1;
%Creating sub-matrix based on amount of trimming%
Sub_Matrix = zeros(M-(2*Trim_Amount),M-(2*Trim_Amount));
for Row = 1: length(Sub_Matrix)
for Column = 1: length(Sub_Matrix)
% fprintf("(%d,%d)\n",Row,Column);
Sub_Matrix(Row,Column) = Matrix(Row + Row_Start_Limit-1,Column + Column_Start_Limit-1);
end
end
end
Ran using MATLAB R2019b

Related

Explanation for a function within xcorr in MATLAB

Looking within the xcorr function, most of it is pretty straightforward, except for one function within xcorr called "findTransformLength".
function m = findTransformLength(m)
m = 2*m;
while true
r = m;
for p = [2 3 5 7]
while (r > 1) && (mod(r, p) == 0)
r = r / p;
end
end
if r == 1
break;
end
m = m + 1;
end
With no comments, i fail to understand what this function is meant to acheive and what is the significance of p = [2 3 5 7]. Why those numbers specifically? Why not take a fixed FFT size instead? Is there a disadvantage(cause errors) to taking a fixed FFT size?
This part is used to get the integer closest to 2*m that can be written in the form:
Either:
m is already of this form, then the loop
for p = [2 3 5 7]
while (r > 1) && (mod(r, p) == 0)
r = r / p;
end
end
Will decrease r down to 1 and the break will be reached.
Or m has at least one other prime factor, and r will not reach 1. You go back to the look with m+1 and so on until you reach a number of the right form.
As per why they do this, you can see on the fft doc, in the Input arguments section:
n — Transform length [] (default) | nonnegative integer scalar
Transform length, specified as [] or a nonnegative integer scalar.
Specifying a positive integer scalar for the transform length can
increase the performance of fft. The length is typically specified as
a power of 2 or a value that can be factored into a product of small
prime numbers. If n is less than the length of the signal, then fft
ignores the remaining signal values past the nth entry and returns the
truncated result. If n is 0, then fft returns an empty matrix.
Example: n = 2^nextpow2(size(X,1))

"out of memory" error for mvregress in matlab

I am trying to use mvregress with the data I have with dimensionality of a couple of hundreds. (3~4). Using 32 gb of ram, I can not compute beta and I get "out of memory" message. I couldn't find any limitation of use for mvregress that prevents me to apply it on vectors with this degree of dimensionality, am I doing something wrong? is there any way to use multivar linear regression via my data?
here is an example of what goes wrong:
dim=400;
nsamp=1000;
dataVariance = .10;
noiseVariance = .05;
mixtureCenters=randn(dim,1);
X=randn(dim, nsamp)*sqrt(dataVariance ) + repmat(mixtureCenters,1,nsamp);
N=randn(dim, nsamp)*sqrt(noiseVariance ) + repmat(mixtureCenters,1,nsamp);
A=2*eye(dim);
Y=A*X+N;
%without residual term:
A_hat=mvregress(X',Y');
%wit residual term:
[B, y_hat]=mlrtrain(X,Y)
where
function [B, y_hat]=mlrtrain(X,Y)
[n,d] = size(Y);
Xmat = [ones(n,1) X];
Xmat_sz=size(Xmat);
Xcell = cell(1,n);
for i = 1:n
Xcell{i} = [kron([Xmat(i,:)],eye(d))];
end
[beta,sigma,E,V] = mvregress(Xcell,Y);
B = reshape(beta,d,Xmat_sz(2))';
y_hat=Xmat * B ;
end
the error is:
Error using bsxfun
Out of memory. Type HELP MEMORY for your options.
Error in kron (line 36)
K = reshape(bsxfun(#times,A,B),[ma*mb na*nb]);
Error in mvregress (line 319)
c{j} = kron(eye(NumSeries),Design(j,:));
and this is result of whos command:
whos
Name Size Bytes Class Attributes
A 400x400 1280000 double
N 400x1000 3200000 double
X 400x1000 3200000 double
Y 400x1000 3200000 double
dataVariance 1x1 8 double
dim 1x1 8 double
mixtureCenters 400x1 3200 double
noiseVariance 1x1 8 double
nsamp 1x1 8 double
Okay, I think I have a solution for you, short version first:
dim=400;
nsamp=1000;
dataVariance = .10;
noiseVariance = .05;
mixtureCenters=randn(dim,1);
X=randn(dim, nsamp)*sqrt(dataVariance ) + repmat(mixtureCenters,1,nsamp);
N=randn(dim, nsamp)*sqrt(noiseVariance ) + repmat(mixtureCenters,1,nsamp);
A=2*eye(dim);
Y=A*X+N;
[n,d] = size(Y);
Xmat = [ones(n,1) X];
Xmat_sz=size(Xmat);
Xcell = cell(1,n);
for i = 1:n
Xcell{i} = kron(Xmat(i,:),speye(d));
end
[beta,sigma,E,V] = mvregress(Xcell,Y);
B = reshape(beta,d,Xmat_sz(2))';
y_hat=Xmat * B ;
Strangely, I could not access the function's workspace, it did not appear in the call stack. This is why I put the function after the script here.
Here's the explanation that might also help you in the future:
Looking at the kron definition, the result when inserting an m by n and a p by q matrix has size mxp by nxq, in your case 400 by 1001 and 1000 by 1000, that makes a 400000 by 1001000 matrix, which has 4*10^11 elements. Now you have four hundred of them, and each element takes up 8 bytes for double precision, that is a total size of about 1.281 Petabytes of memory (or 1.138 Pebibytes, if you prefer), well out of reach even with your grand 32 Gibibyte.
Seeing that one of your matrices, the eye one, contains mostly zeros, and the resulting matrix contains all possible element product combinations, most of them will be zero, too. For such cases specifically, MATLAB offers the sparse matrix format, which saves a lot of memory depending on the number of zero elements in a matrix by only storing nonzero ones. You can convert a full matrix to a sparse representation with sparse(X), or you get an eye matrix directly by using speye(n), which is what I did above. The sparse property propagates to the result, which you should now have enough memory for (I have with 1/4 of your memory available, and it works).
However, what remains is the problem Matthew Gunn mentioned in a comment. I get an error saying:
Error using mvregress (line 260)
Insufficient data to estimate either full or least-squares models.
Preface
If your regressors are all the same across each regression equation and you're interested in the OLS estimate, you can replace a call to mvregress with a simple call to \.
It appears in the call to mlrtrain you had a matrix transposition error (since corrected). In the language of mvregress, n is the number of observations, d is the number of outcome variables. You generate a matrix Y that is d by n. But THEN when you should call mlrtrain(X', Y') not mlrtrain(X, Y).
If below isn't specifically, what you're looking for, I suggest you precisely define what you're trying to estimate.
What I would have written if I were you
So much that's been said here is completely off base that I'm posting code of what I would have written if I were you. I've reduced the dimensionality to show the equivalence in your special case to simply calling \. I've also written stuff in a more standard way (i.e. having observations run down the rows and not making matrix transposition errors).
dim=5; % These can go way higher but only if you use my code
nsamp=20; % rather than call mvregress
dataVariance = .10;
noiseVariance = .05;
mixtureCenters=randn(dim,1);
X = randn(nsamp, dim)*sqrt(dataVariance ) + repmat(mixtureCenters', nsamp, 1); %'
E = randn(nsamp, dim)*sqrt(noiseVariance); %noise should be mean zero
B = 2*eye(dim);
Y = X*B+E;
% without constant:
B_hat = mvregress(X,Y); %<-------- slow, blows up with high dimension
B_hat2 = X \ Y; %<-------- fast, fine with higher dimensions
norm(B_hat - B_hat2) % show numerical equivalent if basically 0
% with constant:
B_constant_hat = mlrtrain(X,Y) %<-------- slow, blows up with high dimension
B_constant_hat2 = [ones(nsamp, 1), X] \ Y; % <-- fast, and fine with higher dimensions
norm(B_constant_hat - B_constant_hat2) % show numerical equivalent if basically 0
Explanation
I'll assume you have:
An nsamp by dim sized data matrix X.
An nsamp by ny sized matrix of outcome variables Y
You want the results from regressing each column of Y on data matrix X. That is, we're doing multivariate regression but there's a common data matrix X.
That is, we're estimating:
y_{ij} = \sum_k b_k * x_{ik} + e_{ijk} for i=1...nsamp, j = 1...ny, k=1...dim
If you're trying to do something different than this, you need to clearly state what you're trying to do!
To regress Y on X you could do:
[beta_mvr, sigma_mvr, resid_mvr] = mvregress(X, Y);
This appears to be horribly slow. The following should match mvregress for the case where you're using the same data matrix for each regression.
beta_hat = X \ Y; % estimate beta using least squares
resid = Y - X * beta_hat; % calculate residual
If you want to construct a new data matrix with a vector of ones, you would do:
X_withones = [ones(nsamp, 1), X];
Further clarification for some that are confused
Let's say we want to run the regression
y_i = \sum_j x_{ij} + e_i i=1...n, j=1...k
We can construct the data matrix n by k datamatrix X and an n by 1 outcome vector y. The OLS estimate is bhat = pinv(X' * X) * X' * y which can also be computed in MATLAB with bhat = X \ y.
If you want to do this multiple times (i.e. run multivariate regression on the same data matrix X), you can construct an outcome matrix Y where EACH column represents a separate outcome variable. Y = [ya, yb, yc, ...]. Trivially, the OLS solution is B = pinv(X'*X)*X'*Y which can be computed as B = X \ Y. The first column of B is the result of regressing Y(:,1) on X. The second column of B is the result of regressing Y(:,2) on X, etc... Under these conditions, this is equivalent to a call to B = mvregress(X, Y)
Even more test code
If regressors are the same and estimation is by simple OLS, there is an equivalence between multivariate regression and equation by equation ordinary least squares.
d = 10;
k = 15;
n = 100;
C = RandomCorr(d + k, 1); %Use any method you like to generate a random correlation matrix
s = randn(d+k , 1) * 10;
S = (s * s') .* C; % generate covariance matrix
mu = randn(d+k,1);
data = mvnrnd(ones(n, 1) * mu', S);
Y = data(:,1:d);
X = data(:,d+1:end);
[b1, sigma] = mvregress(X, Y);
b2 = X \ Y;
norm(b1 - b2)
You will notice b1 and b2 are numerically equivalent. They are equivalent even though sigma is EXTREMELY different from zero.

Matlab - indexing

I have a matrix A which is 21x1 and contains only ones and twos.
Then I have a matrix B which is 6 * 600 matrix of numbers ranging between 0 and 21.
I want to generate a matrix C which is 6 * 600 matrix containing ones and twos such that:
If B matrix has a zero, matrix C should have a zero on that place. If B matrix has number 5, then matrix C should have the element on row 5 of matrix A and so on and so forth.
Please let me know if this is not clear.
Let us generate some sample inputs:
A = randi(2,21,1);
B = randi(22,6,600)-1;
The output C will then be:
C = B*0; %// preallocation + take care of the elements that need to be 0
C(B>0) = A(B(B>0)); %// logical indexing
The explanation of the 2nd line is as follows:
RHS
B>0 - return a logical array the size of B which has the meaning of whether this specific element of B is larger-than-0 value.
B(B>0) - return the elements of B for which there are true values in B>0 (i.e. numbers that can be used to index into A).
A(...) - return the elements of A that correspond to the valid indices from B.
% Generate matrices fitting the description
A = round(rand(21,1))+1;
B = round(rand(6,600)*21);
C = zeros(6,600);
% Indexing impossible since zeroes cannot be used as index. So treat per element using linear indexing.
for ii = 1:(6*600)
if B(ii) == 0
C(ii) = 0;
else
C(ii) = A(B(ii));
end
end
Although the piece of code could be optimized further this is the most clear way of creating understanding and speed is not needed if it's only this small matrix evaluated a limited number of times.

Why does my function return two values when I only return one?

So I'm trying to implement the Simpson method in Matlab, this is my code:
function q = simpson(x,f)
n = size(x);
%subtracting the last value of the x vector with the first one
ba = x(n) - x(1);
%adding all the values of the f vector which are in even places starting from f(2)
a = 2*f(2:2:end-1);
%adding all the values of the f vector which are in odd places starting from 1
b = 4*f(1:2:end-1);
%the result is the Simpson approximation of the values given
q = ((ba)/3*n)*(f(1) + f(n) + a + b);
This is the error I'm getting:
Error using ==> mtimes
Inner matrix dimensions must agree.
For some reason even if I set q to be
q = f(n)
As a result I get:
q =
0 1
Instead of
q =
0
When I set q to be
q = f(1)
I get:
q =
0
q =
0
I can't explain this behavior, that's probably why I get the error mentioned above. So why does q have two values instead of one?
edit: x = linspace(0,pi/2,12);
f = sin(x);
size(x) returns the size of the array. This will be a vector with all the dimensions of the matrix. There must be at least two dimensions.
In your case n=size(x) will give n=[N, 1], not just the length of the array as you desire. This will mean than ba will have 2 elements.
You can fix this be using length(x) which returns the longest dimension rather than size (or numel(x) or size(x, 1) or 2 depending on how x is defined which returns only the numbered dimension).
Also you want to sum over in a and b whereas now you just create an vector with these elements in. try changing it to a=2*sum(f(...)) and similar for b.
The error occurs because you are doing matrix multiplication of two vectors with different dimensions which isn't allowed. If you change the code all the values should be scalars so it should work.
To get the correct answer (3*n) should also be in brackets as matlab doesn't prefer between / and * (http://uk.mathworks.com/help/matlab/matlab_prog/operator-precedence.html). Your version does (ba/3)*n which is wrong.

Matrix dimension must agree error in matlab?

I have adapted some existing code for my program but I am coming across an error that I do not know the cause for. I have data with N observations where my goal is to break up the data into increasing smaller subsamples and do calculations on each of the subsamples. To determine the how the subsample size will change, the program finds divisors of N and stores it into an array OptN.
dmin = 2;
% Find OptN such that it has the largest number of
% divisors among all natural numbers in the interval [0.99*N,N]
N = length(x);
N0 = floor(0.99*N);
dv = zeros(N-N0+1,1);
for i = N0:N,
dv(i-N0+1) = length(divisors(i,dmin));
end
OptN = N0 + find(max(dv)==dv) - 1;
% Use the first OptN values of x for further analysis
x = x(1:OptN);
% Find the divisors >= dmin for OptN
d = divisors(OptN,dmin);
function d = divisors(n,n0)
% Find all divisors of the natural number N greater or equal to N0
i = n0:floor(n/2);
d = find((n./i)==floor(n./i))' + n0 - 1; % Problem line
In function divisors is where the problem occurs. I have 'Error using ./ Matrix dimensions must agree.' However, this worked with input data of length 60, but when I try data of length 1058 it gives me the above error.
I think that with large dataset it's possible that find(max(dv)==dv) will returns multiple numbers. So OptN will become a vector, not a scalar.
Then the length of i (BTW not a good name for variable in MATLAB, it's also a complex number i) will be unpredictable and probably different from n causing the dimension error in the next statement.
You can try find(max(dv)==dv,1) instead to get only the first match. Or add a loop.