MATLAB: Adding vectors to a matrix and counting the number of non zeros - matlab

I have the following problem:
A = [] % matrix
Q = [] % number on non zero in each row
for i=1:10
% I generate a path with name path
% add the path to the matrix A
end
% count number on non zero numbers in each row
How can I do that?
Here is an illustrative example:
If the path in first iteration was: path = [ 1 2 3 4 ]
In the second iteration: path = [ 4 5 6 ]
In third iteration: path = [ 7 2 ]
Then A should be like this:
A =
[1 2 3 4 ,
4 5 6 0 ,
7 2 0 0 ]
After, I would like a vector to show me the number of numbers different than zero in each row like so:
Q = [4 3 2]

Given your comments, this is what I would suggest that you do:
Because the actual paths are not known a priori, I would suggest that you store all of the paths in a cell array. Given your for loop condition, I'm assuming that there will be 10 paths. The actual paths we don't know, but we know there will be 10.
Write some code that will figure out the maximum length of path as this will dictate the size of our matrix A.
Create the matrix A then store of all the paths in, with zeroes appended at the end of each path should they not be the size of the maximum length of the path.
Using the matrix A, figure out how many non-zeroes there are.
Without any further ado, here is the code you are seeking. With each step, I will explain what I am doing to get the desired step.
Step #1
pathCellArray = cell(10, 1);
for i = 1 : 10
%// Insert path generation code here...
%// Assume that the variable is called
%// 'path' that stores this path
%//..
pathCellArray{i} = path;
end
This should be self-explanatory. For each path that you generate, store it in its corresponding cell. The reason why we are placing each path in a cell is because the length of each path is variable. We are also doing this so we can figure out how many columns we need to allocate for A. Also take note that I am creating a cell array of columns. The reason why is because when we do a reconstruction and solve for A, it will make things easier.
Step #2
%// Use cellfun that takes in a cell array and we will
%// generate an array as output that contains the
%// size of each path. We will find the maximum of
%// all of these that will dictate our size of A
lengthArray = cellfun(#length, pathCellArray);
numCols = max(lengthArray);
Now this is something cool. You probably have never seen cellfun before. How cellfun works is that we specify a custom function, and cellfun will apply this function to every element to this cell. For the output of cellfun the i'th position of the output is the output of the custom function for each i'th position of the input cell array. As such, what we are doing here is that we are generating a length array (stored as lengthArray) that goes through each cell and figures out how big the path is. lengthArray will thus store how long each path is. Once we do that, we figure out what the longest path is so we know how big A will be.
Step #3
pathCellArrayAppend = cellfun(#(x) [x zeros(1,numCols-length(x))], ...
pathCellArray, 'UniformOutput', false);
A = cell2mat(pathCellArrayAppend);
This code is probably the most complex out of all that you have dealt with. What I am basically doing here is taking that cell array of paths that I created, and generating a new cell array where each element in the cell (which is our path) gets appended with zeroes up until the length of the longest path. If you look, the custom function we have generated basically creates the array that first stores the path that we want, then zero-pads the rest of the array with zeroes. We have to specify UniformOutput to false as because the output of the the custom function is no longer a single value. It is an array as the output, which is why this flag is set to false. The output of this call to cellfun will generate 10 cell arrays where each element is a path and is zero-padded with zeroes. We then call cell2mat to convert this cell array back to matrix form, and A is your result.
Step #4
Q = cellfun(#(x) sum(x ~= 0), pathCellArrayAppend);
We thus call cellfun again. This time we take a look at our cell array that has all of the paths that are zero-padded. We go through each cell, and count how many non-zero entries there are. Q will store this result. Note that we don't need to set UniformOutput to false as the output of the custom function is a single number.
Using your example that you have provided, here is how the code will look with their corresponding outputs:
%// Step #1 - Simulated
p1 = [1 2 3 4];
p2 = [4 5 6];
p3 = [7 2];
pathCellArray = {p1; p2; p3};
%// Step #2
lengthArray = cellfun(#length, pathCellArray)
>> lengthArray =
4
3
2
numCols = max(lengthArray)
>> numCols =
4
%// Step #3
pathCellArrayAppend = cellfun(#(x) [x zeros(1,numCols-length(x))], ...
pathCellArray, 'UniformOutput', false);
A = cell2mat(pathCellArrayAppend)
>> A =
1 2 3 4
4 5 6 0
7 2 0 0
%// Step #4
Q = cellfun(#(x) sum(x ~= 0), pathCellArrayAppend)
>> Q =
4
3
2
NB: You could simply use Step #2 as your Q, provided that your paths are non-zero. If there are, then you need to go right to Step #4.

Related

Extracting a matrix from a cell vector in MATLAB

A sparse matrix is a large matrix with almost all elements of the same
value (typically zero). The normal representation of a sparse matrix
takes up lots of memory when the useful information can be captured
with much less. A possible way to represent a sparse matrix is with a
cell vector whose first element is a 2-element vector representing the
size of the sparse matrix. The second element is a scalar specifying
the default value of the sparse matrix. Each successive element of the
cell vector is a 3-element vector representing one element of the
sparse matrix that has a value other than the default. The three
elements are the row index, the column index and the actual value.
Write a function called "sparse2matrix" that takes a single input of a
cell vector as defined above and returns the output argument called
"matrix", the matrix in its traditional form. Consider the following
run:
cellvec = {[2 3], 0, [1 2 3], [2 2 -3]};
matrix = sparse2matrix(cellvec)
matrix =
0 3 0
0 -3 0
Good morning/afternoon/night, everyone
I was wondering if you could help me with this.
I am trying to complete this, but I am not sure how to deal with this. I understand that I am interested in the first part of the cell vector, but I am not sure about how to tell Matlab I need that. This is my code:
function matrix = sparse2matrix(x)
A = [2 3];
B = 0;
C = [1, 2, 3];
x = {A, 0, C};
matrix = cell2mat(x);
end
The result of this code is different from the result I showed above.
I am not getting the right answer and honestly I do not know what to do, so I would appreciate if you guide me a little bit.
Not the most elegant way of doing it but it gets the job done. Uses the cell2mat() function and indexing to grab the necessary values for each step. A for-loop is then used to obtain the 3-element vectors that is used to change the array values from the default values in the respective indices.
cellvec = {[2 3], 0, [1 2 3], [2 2 -3]};
[matrix] = sparse2matrix(cellvec)
function [matrix] = sparse2matrix(x)
Matrix_Size = cell2mat(x(1,1));
Matrix_Height = Matrix_Size(1);
Matrix_Width = Matrix_Size(2);
Default_Value = cell2mat(x(1,2));
matrix = Default_Value*ones(Matrix_Height,Matrix_Width);
Triplets = x(3:end);
Number_Of_Triplets = length(Triplets);
for Triplet_Index = 1: Number_Of_Triplets
Current_Triplet = cell2mat(Triplets(1,Triplet_Index));
Row = Current_Triplet(1,1);
Column = Current_Triplet(1,2);
Value = Current_Triplet(1,3);
matrix(Row,Column) = Value;
end
end
Explanation:
The first line in the local function sparse2matrix() indicates to retrieve row 1, column 1 of the cell array x and then convert it to a matrix. The conversion is done using the cell2mat() function.
Matrix_Size = cell2mat(x(1,1));
Results in:
Matrix_Size = [2 3]
The following line indicates to grab index 1 of the previous array Matrix_Size. This will be used to determine the height of the output array matrix. This is done in a similar fashion to evaluate the Matrix_Width using index 2.
Matrix_Height = Matrix_Size(1);
Results in:
Matrix_Height = 2
Ran using MATLAB R2019b

MATLAB. How to remove rows, if any of the values in the row is found in another row?

I have a matrix as shown in the image. In this matrix if any of the values in one row is found in another row we remove the shorter row. For example row 2 to row 5 all contain 3, therefore I want to keep only row 5(the row with most non-zero values) and remove all other rows...please suggest a solution.
Thanks
I believe the below code should work. The idea is to sort the matrix first according to the number of elements in the rows, then loop and remove the rows that have matches. Probably not the most efficient code but should work in principle.. see the comments for more explanation
% generating the data
M = zeros(6, 10);
M(2,1:3) = [3 8 10];
M(3,1:4) = [3 8 10 9];
M(4,1:5) = [3 8 10 9 7];
M(5,1:6) = [3 8 10 9 7 4];
M(6,1) = [5];
% sorting according to the number of non-zero elements
nr_of_nonzero = sum(M~=0, 2);
[~, sort_indices] = sort(nr_of_nonzero);
M_sorted = M(sort_indices,:);
M_sorted(M_sorted==0)=NaN; % should not compare 0s (?)
% get rid of the matches
for i=1:size(M_sorted, 1)-1
for j=(i+1):size(M_sorted, 1)
[C,ia,ib] = intersect(M_sorted(i,:),M_sorted(j,:));
if numel(C)>0
M_sorted(i,:) = NaN;
end
break;
end
end
% reorder
M(sort_indices,:) = M_sorted;
% remove all NaN rows
M(all(isnan(M),2),:) = [];
% back to 0s
M(isnan(M)) = 0;
I'm not doing all the code here, but here's the steps that I would take to solve it. You will likely have to try different ways of doing it to obtain the intended result (i.e. vector operations, while loop, for loop, etc.).
Problem
Rows are repetitive and need to be reduced in a more compact form.
Solution
Look up mat2str.
Convert your vectors (rows) to strings. This can be done with temporary values like tmpstr1 = mat2str(yourMatrix(rowToBeCompared, :));
Parse the first string from beginning to end, while parsing the second string in the same way to make comparisons.
use strcmp to see if the string characters (or strings themselves) are the same: http://www.mathworks.com/help/matlab/ref/strcmp.html
Delete a row if you find it appropriate with yourMatrix[rowToDelete, : ] = [];
Try that and see if it works.
Note - Expansion of step 3:
if we have variable a = '[ab+11]';, we can select individual characters from the string like:
a(4)
ans = '+'
a(5)
ans = '1'
a(1)
and = '['
Therefore, you can parse the string with a loop:
for n = 1 : length(a)
if a(n) == '1' || a(n) == '0'
str(n) = a(n);
end
end
Like Sardar Usama said, it's helpful to provide the code so that we can copy and paste into our own MATLAB workspaces.

Make vectors of unequal length equal in length by reducing the size of the largest ones

I am reading 5 columns from a .txt file to 5 vectors.
Sometimes some vectors are one element larger than others, so I need to check if they are all of equal length, and if not, I have to find which ones are the largest and delete their last element. I think I should be able to do this without loops. I was originally thinking of using find in combination with isequal but isequal only returns a logical, and does not provide any information on which vectors are the largest.
[Seconds,Sensor1VStatic,Sensor2VPulsed,TemperatureC,RelativeHumidity] = importfile(path);
Then depending on what vectors are longer by one element, I will do, for example
Seconds(end) = [];
Sensor1VStatic(end) = [];
If Seconds and Sensor1VStatic are longer than the other vectors by one element
Assume your vectors are in a cell array A:
A = {[1 2 3], [1 2 3 4], [1 2 3 4 5]};
You can get the size of each vector with
sz = cellfun(#(x)size(x,2), A);
Which will return (for the above example)
sz = [ 3 4 5]
Now you can find the shortest vector:
minLength = min(sz);
And finally, make all vectors this length:
B = cell2mat(cellfun(#(x)x(1:minLength), A, 'uniformoutput', false))';
There may be more elegant ways (and note that cellfun really is doing "implicit looping")
Applying this to your (now expanded) example, you could probably assign the output of importfile directly to the cell array - or you can do it as a separate line:
A = {Seconds,Sensor1VStatic,Sensor2VPulsed,TemperatureC,RelativeHumidity};
But it all becomes a lot of work. Instead you could do:
minLength = min(size(Seconds,1), size(Sensor1VStatic,1), size(Sensor2VPulsed,1), ...
Seconds = Seconds(1:minLength);
...
There is scope for some cleverness but it won't make things more readable, and it won't save time in the long run...

Vectorizing the Notion of Colon (:) - values between two vectors in MATLAB

I have two vectors, idx1 and idx2, and I want to obtain the values between them. If idx1 and idx2 were numbers and not vectors, I could do that the following way:
idx1=1;
idx2=5;
values=idx1:idx2
% Result
% values =
%
% 1 2 3 4 5
But in my case, idx1 and idx2 are vectors of variable length. For example, for length=2:
idx1=[5,9];
idx2=[9 11];
Can I use the colon operator to directly obtain the values in between? This is, something similar to the following:
values = [5 6 7 8 9 9 10 11]
I know I can do idx1(1):idx2(1) and idx1(2):idx2(2), this is, extract the values for each column separately, so if there is no other solution, I can do this with a for-loop, but maybe Matlab can do this more easily.
Your sample output is not legal. A matrix cannot have rows of different length. What you can do is create a cell array using arrayfun:
values = arrayfun(#colon, idx1, idx2, 'Uniform', false)
To convert the resulting cell array into a vector, you can use cell2mat:
values = cell2mat(values);
Alternatively, if all vectors in the resulting cell array have the same length, you can construct an output matrix as follows:
values = vertcat(values{:});
Try taking the union of the sets. Given the values of idx1 and idx2 you supplied, run
values = union(idx1(1):idx1(2), idx2(1):idx2(2));
Which will yield a vector with the values [5 6 7 8 9 10 11], as desired.
I couldn't get #Eitan's solution to work, apparently you need to specify parameters to colon. The small modification that follows got it working on my R2010b version:
step = 1;
idx1 = [5, 9];
idx2 = [9, 11];
values = arrayfun(#(x,y)colon(x, step, y), idx1, idx2, 'UniformOutput', false);
values=vertcat(cell2mat(values));
Note that step = 1 is actually the default value in colon, and Uniform can be used in place of UniformOutput, but I've included these for the sake of completeness.
There is a great blog post by Loren called Vectorizing the Notion of Colon (:). It includes an answer that is about 5 times faster (for large arrays) than using arrayfun or a for-loop and is similar to run-length-decoding:
The idea is to expand the colon sequences out. I know the lengths of
each sequence so I know the starting points in the output array. Fill
the values after the start values with 1s. Then I figure out how much
to jump from the end of one sequence to the beginning of the next one.
If there are repeated start values, the jumps might be negative. Once
this array is filled, the output is simply the cumulative sum or
cumsum of the sequence.
function x = coloncatrld(start, stop)
% COLONCAT Concatenate colon expressions
% X = COLONCAT(START,STOP) returns a vector containing the values
% [START(1):STOP(1) START(2):STOP(2) START(END):STOP(END)].
% Based on Peter Acklam's code for run length decoding.
len = stop - start + 1;
% keep only sequences whose length is positive
pos = len > 0;
start = start(pos);
stop = stop(pos);
len = len(pos);
if isempty(len)
x = [];
return;
end
% expand out the colon expressions
endlocs = cumsum(len);
incr = ones(1, endlocs(end));
jumps = start(2:end) - stop(1:end-1);
incr(endlocs(1:end-1)+1) = jumps;
incr(1) = start(1);
x = cumsum(incr);

Load values from a text file in MATLAB

I would like to load variables from a text file.
For example, my text file, varA, varB, and varC.
In MATLAB, I would like to give these variables values so that every variable is a 2x2 matrix.
So from the text file containing the above information I would get a matrix that looks like this:
[ 1 2 3 4 5 6;
1 2 3 4 5 6]
Is this possible?
I added a second example to try to make things a little clearer.
My text file, text.txt, looks like this
x1 x2 x3
In MATLAB my .m file gives the values to these variables like
x1 = [1 1; 1 1]
x2 = [2 2; 2 2]
x3 = [3 3; 3 3]
So, when I import my textfile I would get
a = (textfile)
a = [1 1 2 2 3 3 ; 1 1 2 2 3 3]
I basically try to adapt a genetic algorithm (GA) on a very huge problem (of travelling salesman problem (TSP) type). The problem is that every variable I have is a matrix and the crossover, fitness and mutation codes get pretty complicated. And I am having problems of making a random start population as well.
I would like to randomly select, let's say 30 variables, from a list with 256 so that the variable can only be picked once. Each variable however have their own specific values in a 2*2 matrix that cannot be changed.
I would like to use randperm and then put an x before every value making them variables instead of values...
If the data in the text file looks like this (strings separated by spaces):
x1 x2 x3 ...
You can read the strings into a cell array using TEXTSCAN like so:
fid = fopen('file.txt','r');
A = textscan(fid,'%s');
fclose(fid);
A = A{:};
A now stores the strings in a cell array: {'x1'; 'x2'; 'x3'; ...}. Now, to make a variable out of one of these strings and assign it a value, I would use ASSIGNIN:
assignin('base',A{1},[1 2; 1 2]);
This will create a variable x1 in the base workspace and assign it the value [1 2; 1 2]. The first argument can be either 'base' or 'caller' to create a variable in either the MATLAB base workspace or the workspace of the caller function. You would repeat this for each string name in A, giving it whatever value you want.
ALTERNATE OPTION:
This is an alternate answer to the one I gave you above. The above answer addresses the specific problem you raised in your question. This answer gives you a whole other option to potentially avoid doing things the way you were describing them in your question, and it will hopefully make things easier for you...
If I understand your problem, you basically have 256 2-by-2 matrices, and you want to randomly pick 30 of them. Each of these 2-by-2 matrices sounds like it is stored in its own variable (x1 to x256). Instead, I would suggest storing all 256 matrices in just one variable as either a 3-D array:
xArray = zeros(2,2,256); % Initialize all matrices as [0 0; 0 0]
xArray(:,:,1) = [1 1; 2 2]; % This enters a value for the first matrix
or a cell array:
xArray = cell(1,256); % Initializes an empty array of cells
xArray{1} = [1 1; 2 2]; % Enters a value for the first matrix
You would have to initialize all the values first. Then if you want to randomly pick 30 values, you can next randomize the order of either the third dimension of the 3-D array or the order of the cell array by using RANDPERM:
startOrder = 1:256; % The default order of the matrices
index = randperm(256); % Randomly order the numbers 1 to 256
xArray = xArray(:,:,index); % For a 3-d array
xArray = xArray(index); % For a cell array
Then just use the first 30 entries in xArray for your calculations (instead of the individual variables like you were before):
x = xArray(:,:,1); % Puts the first matrix from the 3-D array in x
x = xArray{1}; % Puts the first matrix from the cell array in x
You can keep repeating the use of RANDPERM to keep generating new randomized arrays of matrices. If you have to keep track of which original matrices you are using, you have to add this line after you randomize xArray:
startOrder = startOrder(index);
Now the entries of startOrder will tell you the original position a matrix was in. For example, if the first array entry in startOrder is 40, then the matrix in the first position of xArray was originally the 40th matrix you entered when you initialized xArray.
Hope this helps!