matlab - Accumarray Adjacency Matrix Confusion? - matlab

So I'm trying to create an adjacency matrix, and I'm confused on the difference between accumarray(matrix+1,1) and accumarray(matrix,1).
I did:
matrix = [ 1 3
4 2
1 3
3 1]
adMatrix1 = accumarray(matrix,1);
adMatrix1=adMatrix1~=0;
adMatrix1 = [0 0 1
0 0 0
1 0 0
0 1 0]
and then:
adMatrix2 = accumarray(matrix+1,1);
adMatrix2=adMatrix2~=0;
adMatrix2 = [0 0 0 0
0 0 0 1
0 0 0 0
0 1 0 0
0 0 1 0]
I know that with the "matrix+1", there's an extra row and column of zero's, but I don't understand why you would do it that way. When I looked it up, according to this post I should use "matrix+1", and the best explanation that I got for that was that "because indexing in matlab starts at 1".
I don't understand that at all... if I was trying to create an adjacency matrix, which way is correct? Any help would be greatly appreciated, thanks!

If your node IDs are 0 indexed you need the +1, otherwise you don't. So the question you need to ask is, are your node IDs 0 indexed or 1 indexed?

Does your matrix accept multiple links? If yes, then both results with accumarray above are not correct, since node 1 and 3 are connected 2 times.
Btw, you can consider sparse and full:
full(sparse(matrix(:,1), matrix(:,2), ones(1, size(matrix, 1))))
ans =
0 0 2
0 0 0
1 0 0
0 1 0
ones(1, size(matrix, 1)) is actually a vector of weight.

Related

Generating in Matlab a "modified" diagonal matrix

I want to construct a matrix A in Matlab of dimension w x (m*w) where
each row is full of zeros except m consecutive ones that shift towards the right hand side as we move down to the rows.
Few examples can clarify
w=3,m=4
A=[1 1 1 1 0 0 0 0 0 0 0 0;
0 0 0 0 1 1 1 1 0 0 0 0;
0 0 0 0 0 0 0 0 1 1 1 1]
or
w=3, m=3
A=[1 1 1 0 0 0 0 0 0;
0 0 0 1 1 1 0 0 0;
0 0 0 0 0 0 1 1 1]
or
w=2, m=3
A=[1 1 1 0 0 0;
0 0 0 1 1 1]
I can't see how to proceed and any hint would be extremely helpful.
Step 1. Simplify the problem
If you write the "modified diagonal matrix" you are asking about as a row vector it will always look like the following
% 1 ... 1 0 ... ... 0 ... ... ... ... ... ... ... ... 1 ... 1
% m ones m*w zeros w-1 times the same as before m ones
Step 2. Think how to solve the simplified problem
The fundamental unit you need is a vector of m ones followed by m*w zeros;
Once you have built such vector, you need it to be repeated w times, MATLAB already knows how to do that;
The only thing you miss are the trailing ones: append them;
Now that the vector you were looking for is completed, you need to turn it into a matrix. MATLAB already knows how to do this too.
Final code
Once you understood the above steps, the final behaviour can be achieved even with a one-liner
>> m = 4; w = 3;
>> vec2mat([repmat([ones(1, m) zeros(1, m*w)], 1, w-1) ones(1, m)], w*m)
ans =
1 1 1 1 0 0 0 0 0 0 0 0
0 0 0 0 1 1 1 1 0 0 0 0
0 0 0 0 0 0 0 0 1 1 1 1
About speed
It's true, for loops aren't so slow anymore. I timed my one-liner solution, the trivial for loop and Luis Mendo's solution with eye() and repelem().
Click on images to zoom
Tested on the same machine, with MATLAB R2018a.
As you can see, as long as m and w are quite small, even if you could point out some differences in speed, them won't be noticeable to humans.
Anyway if you are going to work with bigger matrices, it becomes quite obvious which solution is the best.
Here are some approaches:
Using eye and repelem:
A = repelem(eye(w), 1, m);
Using eye and indexing:
A = eye(w);
A = A(1:w, ceil(1/m:1/m:w));
Using eye and kron:
A = kron(eye(w), ones(1,m));
Using singleton expansion:
A = bsxfun(#eq, (1:m).', ceil(1/m:1/m:w)); % Or A = (1:m).'==ceil(1/m:1/m:w);

Generate truth table in MatLab

I want to create a truth table in MatLab with i columns and i2 rows. For example, if i=2, then
T =
[0 0]
[1 0]
[0 1]
[1 1]
Code to do this has already been created here
This is part of a larger project, which requires i large. Efficiency is a concern. Is there more efficient code to create a truth table? Does MatLab have a built in function to do this?
Edit: Sorry about the formatting!
Something like this?
n=2;
d=[0:2^n-1].';
T=dec2bin(d,n)
T =
00
01
10
11
dec2bin will give you a character array, which you can convert to logical, if needed. There's also de2bi that gives you a numeric array directly, but you need a newer version of Matlab and the ordering of the bits is reversed.
Here's Luis Mendo's speedup, which replicates dec2bin (n and d are as above):
T=rem(floor(d*pow2(1-n:0)),2);
ndgrid is very much your friend here:
function t = truthTable(n)
dims = repmat({[false, true]}, 1, n);
[grids{1:n}] = ndgrid(dims{:});
grids = cellfun(#(g)g(:), grids, 'UniformOutput',false);
t = [grids{:}];
First you need to create grids for the number of dimensions in your truth table. Once you have those you can columnize them to get the column vectors you need and you can horizontally concatenate those column vectors to get your truth table.
I imagine the performance of this will be quite competitive.
>> truthTable(2)
ans =
0 0
1 0
0 1
1 1
>> truthTable(4)
ans =
0 0 0 0
1 0 0 0
0 1 0 0
1 1 0 0
0 0 1 0
1 0 1 0
0 1 1 0
1 1 1 0
0 0 0 1
1 0 0 1
0 1 0 1
1 1 0 1
0 0 1 1
1 0 1 1
0 1 1 1
1 1 1 1
>>
>> timeit(#() truthTable(20))
ans =
0.030922626777
EDIT: Use reshape instead of column dereferencing for further performance improvement
function t = truthTable(n)
dims = repmat({[false, true]}, 1, n);
[grids{1:n}] = ndgrid(dims{:});
grids = cellfun(#(g) reshape(g,[],1), grids, 'UniformOutput',false);
t = [grids{:}];
>> timeit(#() truthTable(20))
ans =
0.016237298777
I know this question has been dead a while, but I was wondering the same thing and found a solution I like a lot. Thought I'd share it here:
fullfact(ones(1, i) + 1) - 1

MATLAB Add 1's to matrix elements around a specific element

Using MATLAB, I have a matrix such as:
1 1 0
1 0 1
1 1 1
The aim is to represent the zero's as a mine in a minesweeper program and the values around the 0's should reflect how many mines are adjacent to it.
Therefore creating a vector like this:
1 2 0
1 0 2
1 1 1
I have thought to take elements around the zero as a sub matrix and then add 1, but then it will turn 0's into 1's.
How would I program such a task?
I think this can be achieved by simple convolution plus some post-processing on the resultant matrix as follows:
% Defining a 6x6 matrix of zeros and ones
mineMat=randi(2,6,6)-1;
numberOfMines=conv2(double(~mineMat),ones(3,3),'same').*mineMat;
% Result:
mineMat=
1 0 1 1 0 0
0 0 0 1 0 0
1 1 1 1 1 0
1 1 1 1 0 1
0 1 0 0 0 0
0 1 1 0 0 0
numberOfMines=
3 0 3 3 0 0
0 0 0 3 0 0
2 3 2 3 4 0
1 2 2 4 0 4
0 3 0 0 0 0
0 3 3 0 0 0
Parag's answer would be my first option. Another approach is to use blockproc (Image Processing Toolbox):
blockproc(~M, [1 1], #(x)sum(x.data(:)), 'Bordersize', [1 1], 'TrimBorder', 0).*M
Sounds like you are looking to apply a (two dimensional) filter:
M = [1 1 0; 1 0 1; 1 1 1]==0;
F = filter2(ones(3),M);
F(M)=0
The middle line basically does the work (applying the filter) to create the count. The last line ensures that the mines stay at value 0.

Index an Array using values from a Matrix, Matlab [duplicate]

This question already has answers here:
2D logical matrix from vector of coordinates (Basic matlab)
(2 answers)
Closed 9 years ago.
I would like to use values from a matrix to index an array. I will use a 3x2 matrix in the example but it could be a matrix of any height in the actual code. The array will be 5x5 in the example but could be a square array of any size. The size of the array and height of the matrix have no relationship.
Here is my code
X =
2 1
4 3
1 4
Grid=zeros(5,5)
Grid =
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
So i would like to access points 2,1 4,3 and 1,4 and add one to the value in that location.
I have tried the following code
Grid(X(:,1),X(:,2))=Grid(X(:,1),X(:,2))+1
Which gives this result
Grid =
1 0 1 1 0
1 0 1 1 0
0 0 0 0 0
1 0 1 1 0
0 0 0 0 0
Which is not what I require.
I have tried other ways with no luck, I think i could use a loop or create a FLAT array but don't really want to, I think there must be a more efficient way.
Anyone have any ideas? I'm using Matlab 2012b.
As always thanks for your time and any help you may be able to give.
Edit-1 Required Result
This is the result I would like
Grid =
0 0 0 1 0
1 0 0 0 0
0 0 0 0 0
0 0 1 0 0
0 0 0 0 0
Edit-2
The coordinate matrix may hold duplicate values, so I would like the value in the relative location in the Array (Grid in the example) to show how many times this coordinate occurs. So my solution is
Grid(sub2ind(size(Grid),X(:,1),X(:,2)))=Grid(sub2ind(size(Grid),X(:,1),X(:,2)))+1
Using the answer to 2D logical matrix from vector of coordinates (Basic matlab) that Oleg pointed me to. I managed to solve my question by converting subscripts to linear indexes:
pos = sub2ind(size(Grid), X(:,1), X(:,2));
Grid(pos) = 1;

Working on Binary Data in Matlab

I have loaded a text file test file in matlab. The load function has now created a variable test with values
1 2 3 4 5
2 3 NaN NaN NaN
Now I have a initialized variable X = [0 0 0 0 0 0 0 0 0 0 0] and Y = [0 0 0 0 0 0 0 0 0 0 0].
I want X to read the first row of test variable and corresponding to the number it reads change its value of the element from 0 to 1. Suppose it reads 1, it should change its element X(1) from 0 to 1. Similarly Y should do the same wrt second row of test.
Any idea how should I proceed?
You can index directly into a vector like so:
x=zeros(1,10);%# your zero vector
a=[1,3,7,8]; %# the index of sports you like
x(a)=1 %# change from 0 to 1
x =
1 0 1 0 0 0 1 1 0 0
Going by your comment, I think this is what you want.