Making Tridiagonal matrix in matlab - matlab

I want to make a triadiagonal matrix with matlab, using
full(gallery('tridiag', 10, 1, -4, 6, -4, 1))
and i take that i have too many arguments in the function. Is there another way to do this?
I am trying to make the following matrix:
6 -4 1 0 0
-4 6 -4 1 0
1 -4 6 -4 1
0 1 -4 6 -4
0 0 1 -4 6

Since your matrix is pentadiagonal, I think the best solution is to use spdiags:
>> n = 5;
>> full(spdiags(ones(n,1)*[1,-4,6,-4,1],[-2,-1,0,1,2],n,n));
ans =
6 -4 1 0 0
-4 6 -4 1 0
1 -4 6 -4 1
0 1 -4 6 -4
0 0 1 -4 6
The full is optional and not recommended for large n.

Since there are 5 non-zero diagonals this is not a tridiagonal matrix so you cannot use the tridiag option. You have to manually generate such matrix by means of the diag() function, which allows you to create a matrix with a given diagonal and you can as well select which diagonal you want to write.
You can achieve this therefore by creating 5 different matrices, each of them will have a given non-zero diagonal:
n=5;
B=diag(6*ones(n,1),0)+diag(-4*ones(n-1,1),1)+diag(-4*ones(n-1,1),-1)+diag(1*ones(n-2,1),2)+diag(1*ones(n-2,1),-2);
In this code n=5 is the order of your matrix, then diag(6*ones(n,1),0) will create a vector (length n) with all 6 and such vector will be placed in the 0-th diagonal. Such matrix will have zero elsewhere.
Similarly diag(-4*ones(n-1,1),1) will create a vector (length n-1) with all -4 and such vector will be placed in the 1st superdiagonal. Such matrix will have zero elsewhere and we sum such matrix to the previous one.
And such "chain reaction" goes on until the matrix is fully generated.
Update: I've been looking around the gallery() help and there is indeed an option for a Toeplitz pentadiagonal. You might want to use then
full(gallery('toeppen',5,1,-4,6,-4,1))

I agree that for your huge case a sparse-based solution such as that of Troy Haskin is best. However, it's worth noting that you're precisely constructing a Toeplitz matrix (as Alessiox hinted), and you can use the built-in toeplitz() to do that. All that is needed is to figure out the number of zeros needed for padding the input nonzero elements of the first row and column (this is necessary since toeplitz asserts the size of the matrix to construct from the dimensions of the input vector):
n = 5; %// linear size of result
v = [1,-4,6,-4,1]; %// nonzero diagonal elements symmetrically
mid = ceil(length(v)/2); %// index of diagonal in the input vector
zerosvec = zeros(1,n-mid); %// zeros for padding the rest
colvec = [v(mid:-1:1), zerosvec]; %// first column of the result
rowvec = [v(mid:end), zerosvec]; %// first row of the result
toeplitz(colvec,rowvec) %// toeplitz does the heavy lifting

Related

How do I make a matrix with uniformly increasing elements without loop

0 0 1 1
1 1 2 2
2 2 3 3
3 3 4 4
4 4 5 5
I want to make matrix like above without for loops.
I only know how to do it with a loop.
This is my code
x = [0 0 1 1];
for i = 1:4
x= [x;x(1,:)+i]
end
Is there a way in a vector like function ':'? Or in other ways.
I want to know how to insert an increased element value into a matrix row without loop.
You could use bsxfun:
result = bsxfun(#plus,x,(0:4).')
In Matlab 2016b or newer you can also directly expand singleton dimensions:
result = x + (0:4).'
You can also use cumsum to cumulatively sum down the columns. So create your starting vector, with a matrix of ones underneath for the other rows.
cumsum([0 0 1 1; ones(4,4)]) % ones(n-1, 4) for result with n rows, input 4 columns
This has the advantage of being able to do other step sizes easily
cumsum([0 0 1 1; 2*ones(4,4)]) % steps of 2
Furthermore, it can handle different intervals in each column if we employ repmat
% Row one ↓ interval per col ↓
cumsum([0 0 1 1; repmat([1 2 3 4], 4, 1)]); % Again, use n-1 in place of 4
If you vertically concatenate the row vectors you want and then take the transpose you will get the required result (ie x=[0:4;0:4;1:5;1:5]' in this example).
You can use kron + one of methods suggested here.
kron(hankel(0:4,4:5),[1 1])

negative and positive distance in matlab

I have a 1 by N vector for example (N is 5):
x=[1,2,3,4,5];
I want to create an N-by-N matrix, M, where M(i,j)=x(i)-x(j) and M(j,i) = -1 * M(i,j)
Could anyone give a simple way without a loop?
You can use binary singleton expansion bsxfun:
bsxfun(#minus,x.',x)
or (in version 2016b or later) implicit expansion:
x.'-x
both will result in:
ans =
0 -1 -2 -3 -4
1 0 -1 -2 -3
2 1 0 -1 -2
3 2 1 0 -1
4 3 2 1 0
This method does exactly what you asked for - apply a function to all the combinations of a with b. In your case, a and b are simply x and itself, and the function is minus (which is written with # in bsxfun, or as simple operator - in an implicit expansion).
Since you want to subtract the column j from the row i, you should first write the column x (i.e. x.') that represents the row index, and then row x, that represents the column index.

how to convert edge list to adjacency matrix

I have this code
function adj=edgeL2adjj(e)
Av = [e; fliplr(e)];
nodes = unique(Av(:, 1:2)); % get all nodes, sorted
adj = zeros(numel(nodes)); % initialize adjacency matrix
% across all edges
for i=1:size(Av,1)
adj(nodes==Av(i,1),(nodes==Av(i,2))) = 1;
end
end
to convert an edge list to an adjacency matrix but if I input u=[8 5;1 4;3 5;6 7]
and then I divide u into two set [8 5;1 4], [3 5,6 7] and apply previous code on [3 5;6 7] I will get a 7 x 7 matrix.
but I want a 8 x 8 matrix to any input.
You have a 7x7 matrix because numel(nodes)=7. Indeed node #2 is not present in u. I suggest you to give this function a second input, that is the maximum number of nodes in your network (in this case, 8) and preallocate the adjacency matrix with such input parameter instead of numel(nodes). Or, alternatively, you can preallocate a zeros() square matrix by giving in input not numel(nodes), but the maximum value in input u. The first option will make your code more robust, the second option will make your code robust as long as the 8-th node is in input u.
Also, there is no need for the fliplr(): if your graph is undirected (that is, the adjacency matrix is symmetric) you can rely on such structure inside the for-loop, without concatenation in Av.
Such function can indeed be simplified as follows:
function adj=edgeL2adjj(e)
adj=zeros(max(max(e))); % initialize adjacency matrix
% across all edges
for i=1:size(e,1)
adj(e(i,1),e(i,2))=1;
adj(e(i,2),e(i,1))=1;
end
end
If the input e is your matrix:
e= [8 5;1 4;3 5;6 7];
such code returns
adj =
0 0 0 1 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 1 0 0 0
1 0 0 0 0 0 0 0
0 0 1 0 0 0 0 1
0 0 0 0 0 0 1 0
0 0 0 0 0 1 0 0
0 0 0 0 1 0 0 0
As you can see you simply exploit the input e. The maximum value is 8, so you build a square 8x8 matrix. Also inside the for-loop by swapping the column indices 1 and 2 in e, you automatically take care of the symmetric structure of the adjacency matrix. Finally, this code automatically sort you out in case of missing nodes: indeed, as you can see, the second row and the second column in adj are all-zeros because node #2 is not present in the edge list e.
Note: I do not recommend to split your input edge list. In this manner, you will loose all the global informations regarding your network. Indeed you will have (let's say) two "sub-networks" which you later have to concatenate (in terms of adjacency matrix). That is, if you split e in two sub-matrices, you'll have two adjacency matrices. By taking into account the code as it is now in my answer, the first matrix will be 8x8 whereas the second will be 7x7 because max(max([3 5;6 7]))=7.
If I may, I'd like to offer an altogether different solution to your problem, which avoids looping over all edges (always a good idea to avoid loops in MATLAB!).
Since you have all your row and column indices, your edge list basically already specifies a (albeit sparse) matrix. You can simply allocate the matrix like this:
function adj = edgeL2adjj(e)
r = e(:,1);
c = e(:,2);
vals = ones(size(r));
% maximum node index determines matrix dimensions
n_nodes = max(e(:));
% create sparse matrix
adj = sparse(r, c, vals, n_nodes, n_nodes);
% if really necessary, you can just convert it to a full matrix
adj = full(adj);
end
If you know you always want the graph to have the same dimensions, even if you only use part of your edges as an input to the function, you could just pass n_nodes as an input instead of determining it from e:
function adj = edgeL2adjj(e, n_nodes)

Checking values of two vectors against eachother and then using the column location of equal entries to extract colums from a matrix in matlab

I'm doing a curve fitting problem in Matlab and so far I've set up some orthonormal polynomials along a specified range of x-values with x = (0:0.0001:40);
The polynomials themselves are each a manipulation of that x vector and are stored as a row in a matrix. I also have some have data entries in the form of two vectors - one for the data x-coords and one for the actual values. I need a way to use the x-coords of my data points to find the same values in my continuous x-vector and then take the corresponding columns from my polynomial matrix and add them to a new matrix.
EDIT: To be more clear. I have, for example:
x = [0 1 2 3 4 5]
Polynomial =
1 1 1 1 1 1
0 1 2 3 4 5
0 1 4 9 16 25
% Data values:
x-coord = [1 3 4]
values = [5 3 8]
I want to check the x-coord values against 'x' to find the corresponding columns and then pull out those columns from the polynomial matrix to get:
Polynomial =
1 1 1
1 3 4
1 9 16
If your x, Polynomial, and xcoord are the same length you could use logical indexing which is elegant; something along the lines of Polynomial(x==xcoord). But since this doesn't seem to be the case, there's a less fancy solution with a for-loop and find(xcoord(i)==x)

In a 100 X 2 matrix, how do divide each element in column 2 by a constant?

I have a 100 by 2 matrix. And I'm trying to figure out how to divide all terms in the second column by a constant.
For example, let's say I have this matrix.
[1 2;
3 4;
5 6]
I want to divide the 2nd column by 2.
[1 2/2;
3 4/2;
5 6/2]
So my final matrix will be.
[1 1;
3 2;
5 3]
Thank you.
If your matrix is M then:
M(:,2)=M(:,2)./2;
will divide all terms in the second column by a constant (2). By the way, because the value you divide with is a constant you can also write / instead of ./
If you'd like to assemble a new matrix and not overwrite the first one just write something like this:
A=[M(:,1) M(:,2)./2]
I'm not sure how natan 's equations should be read, but I'd multiply the first matrix
1 2
3 4
5 6
by the matrix
1 0
0 .5
The resulting matrix is
1 1
3 2
5 3