Creating multidimensional sequences in MATLAB [duplicate] - matlab

My question seems wierd, because I know that we can't use a matrix as input in linspace(x1,x2,n) function. But my question is more something like : I have a vector A=linspace(0,Amax,N), and I want to build a serie of vector B_k or big matrix B_k=linspace(0,A(k),N) but without making a for loop that slows down my whole calculation.
% already defined A
rGC=linspace(0,75e-7,N);
for k=1:N
r=rGC(k);
v=linspace(0,A*r,N);
y=f(r,v);
INT=trapz(v,y);
% The same for 8 more integrals
end

Maybe something using interp1, to interpolate something like:
[0 0 0 ... 0 ]
[A(1) A(2) A(3) ... A(N)]
with N rows .... For instance:
N = 5;
Amax = 15;
A = linspace(0, Amax, N);
x = [0 1];
y = zeros(2, N);
y(2, :) = A;
B = interp1(x, y, linspace(0, 1, N))
Which will give:
B =
0 0 0 0 0
0 0.9375 1.8750 2.8125 3.7500
0 1.8750 3.7500 5.6250 7.5000
0 2.8125 5.6250 8.4375 11.2500
0 3.7500 7.5000 11.2500 15.0000
Not sure it will be any faster than a for loop or that even get the point here :)

Related

Is there a way to group matrix elements in matlab?

I am working on a problem which requires me to group array elements and average each group. For example consider the 4 x 4 matrix M,
M = [ 1 0 0 1;
1 0 1 1;
1 1 0 1;
0 0 0 1;]
I want to group this into a 2 x 2 matrix, taking an average of the elements so we would get
M1 = [0.5 0.75;
0.5 0.5;]
does anyone know a way to do this?
Many thanks
You can do this using conv2, and a little indexing, like so:
>> A = conv2(M,ones(2), 'same');
>> A(1:2:end,1:2:end)/4
ans =
0.5000 0.7500
0.5000 0.5000
I think the way to go is to first split your matrix in parts using mat2cell, then apply your functions to each part and merge them to a new matrix:
>> M = [ 1 0 0 1;
1 0 1 1;
1 1 0 1;
0 0 0 1;]
M =
1 0 0 1
1 0 1 1
1 1 0 1
0 0 0 1
>> T=mat2cell(M, [2 2], [2 2])
T =
2×2 cell array
{2×2 double} {2×2 double}
{2×2 double} {2×2 double}
>> M1 = cellfun(#mean, cellfun(#mean, T, 'UniformOutput', false))
M1 =
0.5000 0.7500
0.5000 0.5000
>>
You can do something like this for any rectangle, where x and y denote the size of domains that you want to average.
function M1 = get_means(M, x, y)
[rows, cols] = size(M);
if mod(rows, x) == 0 && mod(cols, y) == 0
for i = 1:y:cols
for j = 1:x:rows
M1((j+x-1)/x, (i+y-1)/y) = sum(M(j:j+x-1,i:i+y-1),'all')/(x*y);
end
end
else
error('The matrix doesn''t have compatible dimensions.')
end
end
You can loop over the grouped matrices and then calculate the mean
M = [ 1 0 0 1;
1 0 1 1;
1 1 0 1;
0 0 0 1;];
n=2; % 2x2 mat
% create new matrix with means
MM = zeros(n,n);
% row counter for mean-Matrix
r=1;
% loop over matrix groups
for row=1:n:size(M,1)
c = 1; % column counter for mean-Matrix
for col=1:n:size(M,2)
MM(r,c) = mean(mean(M(row:row+n-1, col:col+n-1)));
c = c+1;
end
r = r+1;
end
Output:
MM =
0.5000 0.7500
0.5000 0.5000

How to improve this code for replacing elements of a matrix from another matrices in MATLAB?

So I have these 4 same-sized matrices:
k = [0.5; 1.0; 1.5; 2.0];
l = [2; 4; 6; 8];
m = [1.7; 3.0; 4.5; 6.0];
n = [2.5; 5.0; 7.5; 10.0];
And I want to put the elements from each matrix into the diagonal of zero matrix, so it would create something like this:
f = 0.5 2.0 0 0 0 0 0 0
1.7 2.5 0 0 0 0 0 0
0 0 1.0 4.0 0 0 0 0
0 0 3.0 5.0 0 0 0 0
0 0 0 0 1.5 6.0 0 0
0 0 0 0 4.5 7.5 0 0
0 0 0 0 0 0 2.0 8.0
0 0 0 0 0 0 6.0 10.0
This is what I've come up with:
f = zeros(8,8);
k = [0.5; 1.0; 1.5; 2.0];
l = [2; 4; 6; 8];
m = [1.7; 3.0; 4.5; 6.0];
n = [2.5; 5.0; 7.5; 10.0];
for i = 1:2:8 %odd index number
for j = 2:2:8 %even index number
f(i,i) = k(1,i)
f(i,j) = l(1,i)
f(j,i) = m(1,i)
f(j,j) = n(i,1)
end;
end;
disp(f)
But the result put the elements not into the diagonal of matrix f=zero(8,8), and I've always got the error of Index exceeds matrix dimensions.
Can I get some pointers on how to fix this code?
I think you intended to write this:
for i = 2:2:8
f(i-1,i-1) = k(i/2)
f(i-1,i) = l(i/2)
f(i,i-1) = m(i/2)
f(i,i) = n(i/2)
end
Though there must be simpler ways to accomplish the same thing. For example, check out the function blkdiag!
If you're looking for compact, then here's an interesting solution using eye, repelem, and logical indexing:
>> f = zeros(8);
>> f(repelem(eye(4, 'logical'), 2, 2)) = [k m l n].';
f =
0.5000 2.0000 0 0 0 0 0 0
1.7000 2.5000 0 0 0 0 0 0
0 0 1.0000 4.0000 0 0 0 0
0 0 3.0000 5.0000 0 0 0 0
0 0 0 0 1.5000 6.0000 0 0
0 0 0 0 4.5000 7.5000 0 0
0 0 0 0 0 0 2.0000 8.0000
0 0 0 0 0 0 6.0000 10.0000
Cris Luengo's answer is more flexible and read much better than what I have here, but this is something you probably want to learn if you will do a lot of work using MATLAB.
(This method generally performs better because it removes the need of a for loop.)
k = [0.5;1.0;1.5;2.0];
l = [2;4;6;8];
m = [1.7;3.0;4.5;6.0];
n = [2.5;5.0;7.5;10.0];
f = zeros(8); % to create a square matrix, you only need to specify the size with one value
f(1:18:end) = k;
f(9:18:end) = l;
f(2:18:end) = m;
f(10:18:end) = n;
Here, f is used as if it is a vector (array) even though it is a 8*8 matrix. In Matlab, you can access a single element from a matrix by either specifying the row and column number or linear indexing.
More details can be found here: https://uk.mathworks.com/help/matlab/math/matrix-indexing.html (see Linear Indexing)
Another option is to construct the diagonal, and the two off-diagonal vectors first and then use diag to create the matrices and then adding them together.
%Data
k = [0.5;1.0;1.5;2.0];
l = [2;4;6;8];
m = [1.7;3.0;4.5;6.0];
n = [2.5;5.0;7.5;10.0];
%Construct vectors
diagonal = [1;0].*k.' + [0;1].*n.'; %Diagonal of the matrix
offu = [1;0].*l'; %Upper diagonal
offl = [1;0].*m'; %Lower diagonal
A = diag(diagonal(:)) + diag(offu(1:end-1),1) + diag(offl(1:end-1),-1);
I have no idea whether it is faster than the other answers, but I like its transparency of what is happening.
NOTE: In order to construct the variables diagonal, offu and offl I am using implicit expansion which requires Matlab R2016b or newer. If you are using an older version, you can instead use bsxfun.
A sorry, I missed the everything is shifted. My former answer was completely incorrect...
I still would go for something with blkdiag, you just need to redistribute your matrices:
k = [0.5; 1.0; 1.5; 2.0];
l = [2; 4; 6; 8];
m = [1.7; 3.0; 4.5; 6.0];
n = [2.5; 5.0; 7.5; 10.0];
Y = arrayfun(#(i) [k(i), l(i); m(i), n(i)], 1:4, 'UniformOutput', false);
blkdiag(Y{:})
X = cat(3, [k, m], [l, n]);
blkdiag(squeeze(X(1,:,:)), squeeze(X(2,:,:)), squeeze(X(3,:,:)), squeeze(X(4,:,:)))

Linspace using matrix input matlab

My question seems wierd, because I know that we can't use a matrix as input in linspace(x1,x2,n) function. But my question is more something like : I have a vector A=linspace(0,Amax,N), and I want to build a serie of vector B_k or big matrix B_k=linspace(0,A(k),N) but without making a for loop that slows down my whole calculation.
% already defined A
rGC=linspace(0,75e-7,N);
for k=1:N
r=rGC(k);
v=linspace(0,A*r,N);
y=f(r,v);
INT=trapz(v,y);
% The same for 8 more integrals
end
Maybe something using interp1, to interpolate something like:
[0 0 0 ... 0 ]
[A(1) A(2) A(3) ... A(N)]
with N rows .... For instance:
N = 5;
Amax = 15;
A = linspace(0, Amax, N);
x = [0 1];
y = zeros(2, N);
y(2, :) = A;
B = interp1(x, y, linspace(0, 1, N))
Which will give:
B =
0 0 0 0 0
0 0.9375 1.8750 2.8125 3.7500
0 1.8750 3.7500 5.6250 7.5000
0 2.8125 5.6250 8.4375 11.2500
0 3.7500 7.5000 11.2500 15.0000
Not sure it will be any faster than a for loop or that even get the point here :)

linprog (Matlab) vs glpk(Octave) - Why do I get different solutions?

I need to find an initial feasible solution for a network flow problem which is given by Nx = b, x >= 0. I used to the following OCTAVE code to do the job:
function [x,exitflag] = FIND_EXTREME_POINT(A,b)
%
% Function FIND_EXTREME_POINT
%
% Call: [x,fval] = FIND_EXTREME_POINT(A,b)
%
% MATLAB code for finding a extreme point of the set X = { x | Ax = b,
% x >= 0} by solving the auxiliary problem
%
% min 1'*y
% s.t. A*x + y = b
% x >= 0
% y >= 0
%
% either to receive a feasible basis solution or to return infeasibility
%
% Inputs:
% A - m*n matrix
% b = m*1 rhs
%
% Output:
% x - n*1 vector respresenting an extreme point
% exitflag - 0 if problem is infeasibile, 1 if the problem is feasible
%
% setup parameters for LP solver
[m,n] = size(A);
A_aux = [A eye(m)];
c_aux = [zeros(1,n) ones(1,m)]';
lb = [zeros(1,n+m)]';
ub = [];
ctype = repmat('S',1,m);
vartype = repmat('C',1,n+m);
% solve auxiliary LP
[xmin, fmin] = glpk(c_aux, A_aux, b, lb, ub, ctype, vartype, 1);
...% driving out artifical variables
The solution given by the glpk-solver matches to my handwritten notes.
For some reason I'm using MATLAB and I've got a problem with the following code:
function [x,exitflag] = FIND_EXTREME_POINT(A,b)
%
% Function FIND_EXTREME_POINT
%
% Call: [x,fval] = FIND_EXTREME_POINT(A,b)
%
% ....
%
% setup parameters for LP solver
[m,n] = size(A);
x = []; % output vector
A_aux = [A eye(m)];
c_aux = [zeros(1,n) ones(1,m)]';
lb = [zeros(1,n+m)]';
ub = [];
% solve auxiliary LP
[xmin,fval] = linprog(c_aux,[],[],A_aux,b,lb,ub);
... % driving out artifical variables
On the one hand the optimal solution xmin computed by the linprog-solver is feasible but on the other hand the function value fval is not zero but it should be so... Where is the mistake in my MATLAB code?
A little example:
N = [1 1 0 0 0 0 0;
-1 0 0 -1 0 0 0;
0 -1 1 0 0 -1 0;
0 0 -1 1 1 0 0;
0 0 0 0 0 1 1;
0 0 0 0 -1 0 -1];
b = [5 -5 0 0 0 0]';
OCTAVE gives me:
xmin =
5
0
0
0
0
0
0
0
0
0
0
0
0
fval =
0
MATLAB gives me:
xmin =
0.2184
4.7816
4.7816
4.7816
0.0000
0.0000
0.0000
0.0000
0.0000
0.0000
0.0000
0.0000
0.0000
fval =
5.8775e-016

Solve a system of equations with a constraint to x in Matlab

I have given a nxn upper triangular matrix R and I want to solve the system of equations Rx=0 where x is a vector of size n. Moreover the lowermost diagonalement of R is 0 (R(n,n)=0). Therefore I want to set x(n)=1.
I tried some loops but I do not know how to solve it.
Thank you for your help.
It's guaranteed that R has a zero eigenvalue, and the solution you want is a multiple of the eigenvector corresponding to that eigenvalue. Let's create some matrix R first:
>> R = triu(rand(3, 3));
>> R(3, 3) = 0;
>> R
R =
0.8147 0.9134 0.2785
0 0.6324 0.5469
0 0 0
Now let's get the eigenvalues and eigenvectors:
>> [V, E] = eig(R)
V =
1.0000 -0.9806 0.4289
0 0.1958 -0.5909
0 0 0.6833
E =
0.8147 0 0
0 0.6324 0
0 0 0
The eigenvectors are the diagonal elements of E
>> E = diag(E);
>> index = find(abs(E) < 1e-16); %// NB don't use find(E==0) because of fp problems...
Now pull out the correct eigenvector
>> v = V(:, index);
and make sure its final element is equal to 1
>> v = v / v(end)
v =
0.6277
-0.8648
1.0000
You can check that this is the solution you want
>> R * v
ans =
0
0
0