About the matrix indexing - matlab

I have a Zeros-matrix P of size (16,16); I need to replace first 4 rows in columns 1:4:end by 1, then next 4 rows in columns 2:4:end by one, and so on.
I have done this, but I noticed that in second rows, the ones are repeated in columns 1 and 2, however what I want is to be only in columns 1:4:end.
Here is the code I made:
P = zeros(16,16);
for i = 1 : 4
P(i:i*4,i:4:end)=1;
end
Could you help to solve that issue. ?

Shift the selected row by (ii-1)*4
P = zeros(16,16);
for ii = 1:4
P([1:4]+(ii-1)*4,ii:4:end)=1;
end
BTW: Avoid to use i as a variable since it's the matlab in-built function that return the imaginary unit.

Related

How to set first 6 rows and all columns to 0 in Matlab

I have a 2-d matrix that I would like to change the first 6 rows and last 6 rows and their corresponding columns to 0.
I have this right now but it is only doing it by a single row.
at_1(4, :) = zeros(1, 141); % set first 6 rows to zero val
This should make the trick
at_1(1:6, :) = 0;
at_1(end-5:end, :) = 0;
You are basically saying to use the values from 1 to 6 in all columns by using (1:6, :) and the second statement is the same but using the end instead.

How to use for loop to delete rows of similar second column element in matlab

I have this matrix:
A=[2,2,4;1,2,3;4,5,6;4,5,6;4,5,6;7,8,9]
How can I use a for loop to delete a row that has its second column element the same as the previous row second column element in matlab? The objective is to arrive at:
A=[2,2,4;4,5,6;7,8,9]
No loop needed!
What you can do here is create a logical vector with true in the places where there is a difference between the second columns, and false where the value is equal:
This can be achieved using diff like this: diff(A(:,2))~=0. Now, you need to include the first row too, so add a true in the start of this vector: [true; diff(A(:,2))~=0)]. Use this vector to choose which rows you want, and use : to make sure you get all the columns:
A=[2,2,4;1,2,3;4,5,6;4,5,6;4,5,6;7,8,9]
B = A([true; diff(A(:,2))~=0],:)
B =
2 2 4
4 5 6
7 8 9
I think this sample code can do the task:
A=[2,2,4;1,2,3;4,5,6;4,5,6;4,5,6;7,8,9]
% First row will always be the same of the A matrix
res_mat(1,:) = A(1,:);
row = 2;
for i = 2 : size(A,1)
if A(i,2) ~= A(i-1,2)
res_mat(row,:) = A(i,:);
row = row + 1;
end
end
res_mat
HTH ;)

MATLAB: For loop structure [duplicate]

This question already has answers here:
Element-wise array replication in Matlab
(7 answers)
Closed 6 years ago.
This is a basic program but since I'm new to MATLAB, I'm not able to figure out the solution.
I have a column vector "Time" in which I want to print value "1" in first 147 cells, followed by "2" in 148 to 2*147 cells and so on. For that, I have written the following script:
Trial>> c=1;
Trial>> k=0;
Trial>> for i = c:146+c
Time(i,1)=1+k;
c=i;
k=k+1;
end
I know I need to iterate the loop over "Time(i,1)=1+k;" before it executes the next statement. I tried using break but that's not supposed to work. Can anyone suggest me the solution to get the desired results?(It was quite simple in C with just the use of curly braces.)
I am sure you don't want to run c=i; in every iteration.
My code should work for you:
x = 10; % Replace 10 by the max number you need in your array.
k = 1;
for i = 1 : x * 147
Time(i, 1) = k;
if rem(i, 147) == 0
k = k + 1;
end
end
This is the prime example of a piece of code that should be vectorized can help you understand vectorization. Your code can be written like this:
n = 147;
reps = 10; %% Replace this by the maximum number you want your matrix to have
Time = reshape(bsxfun(#plus, zeros(n,1), 0:reps), 1, []);
Explanation:
Let A be a column vector (1 column, n rows), and B be a row vector (1 row, m columns.
What bsxfun(#plus, A, B) will do here is to add all elements in A with all elements in B, like this:
A(1)+B(1) A(1)+B(2) A(1)+B(3) ... A(1)+B(m)
A(2)+B(1) A(2)+B(2) ............. A(2)+B(m)
............................................
A(n)+B(1) A(n)+B(2) .............. A(n)+B(m)
Now, for the two vectors we have: zeros(n,1), and 0:reps, this will give us;
0+0 0+1 0+2 0+reps
0+0 0+1 0+2 0+reps
% n rows of this
So, what we need to do now is place each column underneath each other, so that you will have the column with zeros first, then the row with ones, ... and finally the one with reps (147 in your case).
This can be achieved by reshaping the matrix:
reshape(bsxfun(#plus, zeros(n,1), 0:reps), [], 1);
^ ^ ^ ^
| | | Number of rows in the new matrix. When [] is used, the appropriate value will be chosen by Matlab
| | Number of rows in the new matrix
| matrix to reshape
reshape command
Another approach is using kron:
kron(ones(reps+1, 1) * 0:(n-1)
For the record, a review of your code:
You should always preallocate memory for matrices that are created inside loops. In this case you know it will become a matrix of dimensions ((reps+1)*n-by-1). This means you should do Time = zeros((reps+1)*n, 1);. This will speed up your code a lot.
You shouldn't use i and j as variable names in Matlab, as they denote the imaginary unit (sqrt(-1)). You can for instance do: for ii = 1:(n*147) instead.
You don't want c=i inside the loop, when the loop is supposed to go from c to c + 146. That doesn't make much sense.
You can use repmat,
x = 10; % Sequence length (or what ever it can be called)
M = repmat(1:x,147,1); % Replicate array 1:x for 147 columns
M = M(:); % Reshape the matrix so that is becomes a column vector.
I can assume that this is a task to practice for loops, but this will work.
An alternative solution may be to do
n = 147;
reps = 10;
a = ceil( (1:(n*reps)) / n);
You first construct an array with the length you want. Then you divide, and round of upwards. 1 to 147 will then become 1.

Delete rows and columns of a matrix

I have the matrix below:
a = [1 2 1 4;
3 4 9 16;
0 0 -2 -4;
0 0 -6 -8]
How can I arbitrary remove any given rows or columns? for example second row and third column of the above matrix?
Just assign the column or line to the empty matrix:
a(2,:) = [];
a(:,3) = [];
Note : I compare the other solution to mine, following the link put inside. On a big array (created as rand(1e4)) and on 10 runs where I delete 2 columns and 2 rows, the average times are 0.932ms for the empty-matrix assignment, and 0.905ms for the kept-row (or -column) assignment. So the gap seen there is not as big as 1.5x mentioned in the link. Always perform a little benchmark first :) !
Edit Fastest solution is to create the index mask for rows and columns, and reassign your array with these masks. Ex:
a = rand(10000);
kr = true(size(a,1),1);
kr([72,6144]) = false; % some rows to delete
kc = true(1,size(a,2));
kc([1894,4512]) = false; % some columns to delete
a = a(kr,kc);
On this test, it's clearly twice faster than performing the suppression on rows and columns separately.
A slightly more efficient way (although possibly more complicated to set up) is to reassign all the rows you want to keep (when compared with setting the rows you want to delete to the empty matrix). So for example if you want to delete rows 5 and 7 from a matrix you can either do
A = A([1:4, 6, 8:end],:)
or
A = A(setdiff(1:size(A,1), [5,7] ),:)
but the best method is likely to use logical indexing (which is often a natural step in Matlab workflows anyway):
idx = true(size(A,1),1);
idx([5,7]) = false;
A = A(idx,:)

All possible combinations such that sum of all numbers is a fixed number

I need to find all possible combinations of numbers 1:8 such that sum of all elements is equal to 8
The combinations need to be arranged in an ascending order.
Eg
1 7
2 2 4
1 3 5
1 2 2 3
1 1 1 1 1 1 1 1
A number can repeat itself. But a combination must not..
i.e 1 2 2 3 and 2 1 2 3
I need the the solution in ascending order So there will be only one possibility of every combination
I tried a few codes online suggested on Find vector elements that sum up to specific number in MATLAB
VEC = [1:8];
NUM = 8;
n = length(VEC);
finans = zeros(2^n-1,NUM);
for i = 1:(2^n - 1)
ndx = dec2bin(i,n) == '1';
if sum(VEC(ndx)) == NUM
l = length(VEC(ndx));
VEC(ndx)
end
end
but they dont include the possibilities where the numbers repeat.
I found a better approach through recursion and it's more elegant (I like elegant) and faster than my previous attempt (0.00399705213 seconds on my computer).
EDIT: You will need my custom function stretchmat.m that stretches a vector to fit the size of another matrix. Kinda like repmat but stretching the first parameter (see help for details). Very useful!
script.m
% Define funciton to prepend a cell x with a variable i
cellprepend = #(x,i) {[i x]};
% Execute and time function
tic;
a = allcomb(cellprepend,1,8); % Solution in a
toc;
allcomb.m
function a = allcomb( cellprepend, m, n )
% Add entire block as a combination
a{1} = n;
% Exit recursion if block size 1
if n == 1
return;
end
% Recurse cutting blocks at different segments
for i = m:n/2
b = allcomb(cellprepend,i,n-i);
a = [a cellfun( cellprepend, b, num2cell( stretchmat( i, b ) ) )];
end
end
So the idea is simple, for solutions that add to 8 is exhaustive. If you look for only valid answers, you can do a depth first search by breaking up the problem into 2 blocks. This can be written recursively as I did above and is kinda similar to Merge Sort. The allcomb call takes the block size (n) and finds all the ways of breaking it up into smaller pieces.
We want non-zero pieces so we loop it from 1:n-1. It then prepends the first block to all the combinations of the second block. By only doing all comb on one of the blocks, we can ensure that all solutions are unique.
As for the sorting, I'm not quite sure what you mean by ascending. From what I see, you appear to be sorting from the last number in ascending order. Can you confirm? Any sort can be appended to the end of script.m.
EDIT 2/3 Notes
For the permutatively unique case, the code can be found here
Thanks to #Simon for helping me QA the code multiple times
EDIT: Look at my second more efficient answer!
The Naive approach! Where the cartprod.m function can be found here.
% Create all permutations
p(1:8) = {0:8};
M = fliplr( cartprod( p{:} ) );
% Check sums
r = sum( M, 2 ) == 8;
M = M(sum( M, 2 ) == 8,:); % Solution here
There are definitely more efficient solutions than this but if you just need a quick and dirty solution for small permutations, this will work. Please note that this made Matlab take 3.5 GB of RAM to temporarily store the permutations.
First save all combinations with repetitions in a cell array. In order to do that, just use nmultichoosek.
v = 1 : 8;
combs = cell(length(v),0);
for i = v
combs{i} = nmultichoosek(v,i);
end
In this way, each element of combs contains a matrix where each row is a combination. For instance, the i-th row of combs{4} is a combination of four numbers.
Now you need to check the sum. In order to do that to all the combinations, use cellfun
sums = cellfun(#(x)sum(x,2),combs,'UniformOutput',false);
sums contains the vectors with the sum of all combinations. For
instance, sums{4} has the sum of the number in combination combs{4}.
The next step is check for the fixed sum.
fixed_sum = 10;
indices = cellfun(#(x)x==fixed_sum,sums,'UniformOutput',false);
indices contains arrays of logical values, telling if the combination satisfies the fixed sum. For instance, indices{4}(1) tells you if the first combination with 4 numbers sums to fixed_sum.
Finally, retrieve all valid combinations in a new cell array, sorting them at the same time.
valid_combs = cell(length(v),0);
for i = v
idx = indices{i};
c = combs{i};
valid_combs{i} = sortrows(c(idx,:));
end
valid_combs is a cell similar to combs, but with only combinations that sum up to your desired value, and sorted by the number of numbers used: valid_combs{1} has all valid combinations with 1 number, valid_combs{2} with 2 numbers, and so on. Also, thanks to sortrows, combinations with the same amount of numbers are also sorted. For instance, if fixed_sum = 10 then valid_combs{8} is
1 1 1 1 1 1 1 3
1 1 1 1 1 1 2 2
This code is quite efficient, on my very old laptop I am able to run it in 0.016947 seconds.