How to select random elements from row sequentially from matrix but if the all elements in row selected don't select the same row again - matlab

let say i have this matrix
m =
3 1 2 4 6 5
2 3 5 6 1 4
3 4 6 1 2 5
2 1 3 4 5 6
3 2 5 6 1 4
2 4 6 1 5 3
which have 6 raw's and 6 column
i want to select randomly froms raw sequentially the first selection will choose the first
element in that raw
so if by random after covering all the elements in raw 5 i don't want the program to come
to select from it again
example if random iteration 1 select raw1 it will go to the first element in raw1 which is
in column 1
if by random in iteration 2 it select the same raw1 again it will select the the second
element in raw1 which is in column 2
so if i reached column 6 in raw1 and after it the iteration selected raw1 again but my
matrix is 6 column so i want to select by random another raw which is not reached till the
sixth column
let say if each time a raw is selected i will make a value in that column which equal to
one
so if i run 20 iterations
JM =
1 1 1 1 1 0
1 1 0 0 0 0
1 1 1 1 0 0
1 1 0 0 0 0
1 1 1 0 0 0
1 1 1 1 0 0
by luck i didn't reach the sixth column in any of the raws
but if
JM =
1 1 1 1 1 0
1 1 1 1 0 0
1 1 0 0 0 0
1 1 1 1 1 1
1 0 0 0 0 0
1 1 0 0 0 0
Attempted to access m(5,7); index out of bounds because size(m)=[6,6].
how to continue random selection without coming to that raw which already full filled like
that raw 4 is already full filled
i hope it is easy to understand
iam using this method to create chromosome
which is in the form
m raw colmun =machine job operation
thanks
iam using matlab

I can see three slightly different methods to achieve this.
You should create an array of integers to store the information containing amount of elements you already took from each raw. Lets assume your matrix is [n*n] so the array will be [n]. Lets call it a[n]
first method:
Generate random raw number rNumber.
Check if you can take elements from this raw ( if(rNumber] < n) ). If you can't take an element then go to (1). Otherwise continue to (3)
Take an element m[rNumber][a[rNumber]] and increment a[rNumber]
second method:
Generate random raw number rNumber.
Check if you can take elements from this raw ( if(rNumber] < n) )
If you can't take an element then go to increment rNumber and go to (2). Otherwise continue to (4)
Take an element m[rNumber][a[rNumber]] and increment a[rNumber]
The last method also need to store the amount of raws where you took all the elements rawCount.
Generate random raw number rNumber between 0 and n-rawCount-1
Enumerate through all raws while currentRaw < rNumber. If a[currentRaw] < n then increment currentRaw
Take an element m[currentRaw][a[currentRaw]] and increment a[currentRaw]
If a[currentRaw] = n then increment rawCount

here is something that i wrote in c++. hope this is what were you looking for. don't hesitate to ask if you don't understand something
#include "stdafx.h"
#include<fstream>
#include<ctime>
#include<iostream>
using namespace std;
ifstream f("stack2.in");
ofstream g("stack2.out");
int a[10][10];
int solution[100],n,m,index =0;
void build(int n,int m)//create a MxN matrix, and fill it with values
{
int zz = 1;
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
{
a[i][j]= zz;
zz++;
}
}
void solve()
{
srand((unsigned)time(0));
int i,j;//column and line
while(index<m*n)
{
i = (rand()%10);//get random values for column and line
j = (rand()%10);
if(a[i][j]!=0) //if the value of matrix[i][j] is not 0, means that this value is new, so we add it to the solution list
{
solution[index]=a[i][j];
index++;
a[i][j]=0; //set the value from matrix[i][j] to 0 so we don't 'visit' again
}
else if(i<=n) //if the value from the matrix[i][j] is equal to 0, we start searching on the line of of i for values that are not 0
{
while(j<m)
{
if(a[i][j+1]!=0) //if matrix[i][j+1] has not been visited before, we add it to the solution, set it to zero and exit the while
{
solution[index]= a[i][j+1];
a[i][j+1]=0;
index++;
j=m; //exit the while
}
else
j++; //keep searching for a value on that line
}
}
}
for(int i=1;i<=m*n;i++)//print the list with random values
g<<solution[i]<<" ";
}
int main()
{
n=10;//or read the values from stack2.in using f>>n>>m
m=10;//in the file should be written on the same line, number of lines and columens of the matrix eg.: 5 7
build(n,m);
solve();
return 0;
}

Related

Comparing elements in each row of a matrix and count the similar values

I have a matrix like this:
line=[1 3 5 0 0 4 2;
1 3 8 0 8 2 2 ]
I want to compare the rows in this matrix. If the 1st column of the first row is the same as 1st column of second row then increase a counter. But if the value is zero, then the counter should not be increased.
For the example above I expect the output to be match = 3
where the matching values are 1,3,2 so the match = 3
I would go for this:
match = sum((line(1, :) == line(2, :)) & (line(1, :) != 0))
The Array comparison line(1, :) == line(2, :) will give you (logical) 1 at the points, where both rows have identical values:
ans =
1 1 0 1 0 0 1
Next, you need to exclude possible 0 values. That can be done by findind non-zero elements just in the first row (line(1, :) != 0), and then using the & operator on the results. You'll get:
ans =
1 1 0 0 0 0 1
At last, you just have to count the ones using sum.
You can check if the sum of each column divided by the first line equal 2.
So:
count = sum(sum(x)./x(1,:)==2)
Since 0/0 is indetermined, 0 will not be taken into account.

Inserting Ones at pseudo-fixed Intervals

I have the following row vector:
A = zeros(1,200);
I'd like to insert a '1' every 2-3 columns until I have exactly 80 ones in total that are approximately evenly spaced - as opposed to having fixed spacing - with the first 2 columns being zeros.
e.g.
0 0 1 0 1 0 0 1 0 0 1 0 1 ...
It would be nice if the combination could be permuted as well so that more than one row vector satisfies the criteria.
Thanks!
You could use repelem (run-length encoding) to do this. The way that repelem works is that we have two inputs: the values and the number of times each value is repeated.
For example
values = [0 1];
repeats = [1 2];
repelem(values, repeats)
% 0 1 1
We can also have duplicate values in the values array
values = [0 1 0 1];
repeats = [2 1 1 1];
repelem(values, repeats)
% 0 0 1 0 1
We can utilize this to solve your problem.
First we construct the values matrices to simply alternate between 0 and 1 meaning that we want the expanded matrix to contain some 0's followed by a 1, some 0's followed by a 1, etc.
values = ~mod(1:80, 2);
% 0 1 0 1 0 1 0 1 ....
In your case, the number of times each 0 is going to be repeated is going to be either 1 or 2. Each 1 however, is only going to be repeated once. To make this happen we use rand to pick randomly between 1 and 2 repeats. Then we assign all the repeats for 1 values to be a single repeat.
repeats = randi([1 2], size(values));
% Make sure that the 1's are always only repeated once
repeats(values) = 1;
We use 80 entries in the repeats and values arrays just to make sure that we end up with at least 80 values in the final (expanded) array.
Now apply the repelem and keep only the first 80 values
result = repelem(values, repeats);
result = result(1:80);
% 0 1 0 0 1 0 0 1 0 1 0 0 1
You can do this with a few standard functions and array indexing. Something like this ...
A = zeros(1,200);
ixs = round(cumsum(2 + rand(200,1)));
A(ixs(ixs<200))=1;
%Sample result here, first 20 entries: 0 0 1 0 1 0 0 1 0 0 1 0 1 0 0 1 0 1 0 1
What we're doing here is:
Setting up the A array (this is clear)
Defining an oversized array of index values to set to one (more on that below)
Then using that index to set values to one, trimming the oversize.
In terms of creating the index ixs, in innermost portion (2 + rand(200,1)) creates a 200x1 array of values between 2 and 3. Using cumsum generates the cumulative sum of this array, and then round rounds the values to an integer, which can be used for indexing. For example, the first 10 values is ixs look like this, for a particular run:
>> ixs(1:10)'
ans =
3 5 8 11 13 16 18 20 22 24
Since the number of 1 values will vary each time, I set this up to be oversized. That is, the last few values are [487 489 491 497 500], larger than the actual size required. This is why the values need to be trimmed with applying the index.
A = zeros(1,200);
idx = cumsum(1 + randi(2,80,1)); % This is the main trick
A(idx) = 1;
cumsum(1 + randi(2,80,1)) gets you the indexes for exactly 80 elements in A which need to be switched to 1 spaced by 2 or 3 (randomly)

How to select specific rows based upon column attribute values in matlab?

I have [sentence cross words] logical matrix where value = 1 shows presence of a word in that sentence and 0 shows absence like as follows:
0 0 1 1
1 0 1 0
0 0 0 1
1 1 0 0
I have done some processing and selected specific words i.e. 2 & 3
result = 2 3
Now, I want to select only those rows in which value of words 2 & 3 are equal to 1 and return there row number as follows:
row = 1 2 4
This should be done for every word that is in result variable - thanks.
Think you are looking for something like this, assuming A as the input binary array -
result = [2 3]; %// select words by IDs
row = find(any(A(:,result),2))
Sample run -
A =
0 0 1 1
1 0 1 0
0 0 0 1
1 1 0 0
row =
1
2
4
For fun-sake, you can also use matrix-multiplication as an alternative approach -
row = find(A(:,result)*ones(numel(result),1))
First choose the columns that you want to extract and create a matrix that concatenates all of these columns together. Next, use any and operate along the columns in combination with find to obtain the desired locations.
Therefore, given your logical matrix stored in X, do:
ind = [2 3];
matr = X(:,ind);
vals = find(any(matr, 2));
With your above example, we get:
vals =
1
2
4

Create a vector that holds the index of all the columns which has non-zero values based on a condition

I have a matrix filled with zeros and ones and I need to count the number of ones in each row. Then I need to know which row's count exceeds or equal a specific limit (any number, for example 3). After that foreach row in these rows I need to create a vector that holds the index of all the columns which has non-zero values in that row and in all the rows above it and below it till it reach a row with zero count.
Example:
data contains the data below:
0 0 0 0 0 0 0
0 0 0 1 1 0 0
0 1 0 0 1 0 1
0 0 0 0 0 0 0
0 1 0 0 0 0 0
0 1 1 1 0 0 0
0 0 1 0 0 0 0
0 0 0 0 0 0 0
The output should be if the limit is 3:
Row 3: col 4 5 2 5 7
Row 6: col 2 2 3 4 3
I already read the data and I counted the ones in the code below:
load('data');
mat(isnan(mat)) = 0;
[rows,cols,vals] = find(mat~= 0);
unqRows=unique(rows);
countElinRows=histc(rows,unqRows);
Edit for clarification as requested by commentators:
If the third row of the given sample input array becomes [0 1 0 0 0 0 1], then we must only have this output -
Row 6: col 2 2 3 4 3
Assuming A as the input array, see if this works for you -
[sc1,sr1] = find(A') %//'# row and col indices for sorted rows
s_a1 = sum(A,2) %// sum input array along cols
bounds = find(s_a1==0) %// find bounds/gropus delimited by all zero rows
bounds = unique([1 ; bounds ; size(A,1)]) %// account for non all zero
%// starting and ending rows
cumsum1 = cumsum(s_a1==0) + double(sum(A(1,:))~=0) %// label groups
valid_groups = accumarray(cumsum1, s_a1, [], #max)>=3 %// valid groups
out = arrayfun(#(k1) sc1(sr1>=bounds(k1) & sr1<=bounds(k1+1)),...
1:numel(bounds)-1,'un',0) %// find all indices within each group
out = out(valid_groups) %// select only the valid groups for the final output
Visualized output with celldisp(out).
Apologies for strange code, but it's the best I could come up with
[I1,~]=find(sum(mat,2)>=3)
[I2,~]=find(sum(mat,2)==0)
[~,CM]=find(diff(mod(sum(bsxfun(#le,I1,I2.')),2))~=0)
[I,J]=arrayfun(#(t)find(mat(I2(CM(t)):I2(CM(t)+1),:)>0),1:length(CM),'UniformOutput',false)
[~,w]=cellfun(#sort,I,'UniformOutput',false);
J=arrayfun(#(t) J{t}(w{t}).',1:length(J),'UniformOutput',false)
celldisp(J)
This code does feel pretty overcomplicated.
I have tested it on a few cases and it seems to be fine, but it's hard to know for certain.

Midpoints of matrix rows depending on certain conditions Matlab

I have a matrix A with size 10x100 as shown below. What I want to do is:
I'll work row by row in which for each row I'll check the data of
each coloumn in this row
Let's say I'm now in the first col cell in the first row. I'll check if the value is zero I'll move to the next col, and so on till I found a col having a non-zero value and save its col number e.g. col 3 "this means that col 1&2 were zeros"
Now I'm in the first non zero col in row1, I'll move to the next col till I find a col with zero value. I'll fetch the col just before this zero one which must be a non-zero one and save it. e.g col 7 "this means that col4&5&6 are non-zeros and col8 is zero"
Now I want to save the median middle col between this two columns e.g col3 and col7 then the middle col is col5 so I'll save the index row1_col5. if there are two middle values then any of them is fine.
I'll then move to the next col till I find a non-zero col "do the
same steps from 2-->5" till the first row is finished.
Move to the next row and start over again from step 2-->5.
There are two rules: -The first one is that I'll get the middle index of non-zero consecutive values only if there is a minimum of 3 non-zero consecutive values, if there are two non-zero consecutive value then the middle will not be calculated -The second one is that if the number of zero consecutive values are less than 3 then they will be ignored and will be considered as non-zero values. e.g in the below example the first row middle values are col5 and col11. In row2 col5 is counted, while no cols in row3 satisfy this conditions , and in row4 col6 or col7 will be counted.
After finishing all the rows want to have a vector or array holding the positions of all the middle indexes e.g row1_col5 row1_col17 row2_col_10 and so on.
example:
A = [ 0 0 0 2 4 1 0 0 0 1 3 2;
0 0 0 5 1 1 1 1 0 0 0 1;
0 3 4 1 0 3 1 2 0 0 1 3;
0 0 0 0 1 3 4 5 0 0 0 0];
for the first row the middle value will be 5 and 11 and so on
So if anyone could please advise how can I do this with least processing as this can be done using loops but if there is more efficient way of doing it? Please let me know if any clarification is needed.
Now you have clarified your question (again...) here is a solution (still using a for loop...). It includes "rule 7" - excluding runs of fewer than three elements; it also includes the second part of that rule - runs of fewer than three zeros don't count as zero. The new code looks like this:
A = [ 0 0 0 2 4 1 0 0 0 1 3 2;
0 0 0 5 1 1 1 1 0 0 0 1;
0 3 4 1 0 3 1 2 0 0 1 3;
0 0 0 0 1 3 4 5 0 0 0 0];
retVal = cell(1, size(A, 1));
for ri = 1:size(A,1)
temp = [1 0 0 0 A(ri,:) 0 0 0 1]; % pad ends with 3 zeros + 1
% so that is always a "good run"
isz = (temp == 0); % find zeros - pad "short runs of 0" with ones
diffIsZ = diff(isz);
f = find(diffIsZ == 1);
l = find(diffIsZ == -1);
shortRun = find((l-f)<3); % these are the zeros that need eliminating
for ii = 1:numel(shortRun)
temp(f(shortRun(ii))+1:l(shortRun(ii))) = 1;
end
% now take the modified row:
nz = (temp(4:end-3)~=0);
dnz = diff(nz); % find first and last nonzero elements
f = find(dnz==1);
l = find(dnz==-1);
middleValue = floor((f + l)/2);
rule7 = find((l - f) > 2);
retVal{ri} = middleValue(rule7);
end
You have to use a cell array for the return value since you don't know how many elements will be returned per row (per your updated requirement).
The code above returns the following cell array:
{[5 11], [6], [7], [7]}
I appear still not to understand your "rule 7", because you say that "no columns in row 3 satisfy this condition". But it seems to me that once we eliminate the short runs of zeros, it does. Unless I misinterpret how you want to treat a run of non-zero numbers that goes right to the edge (I assume that's OK - which is why you return 11 as a valid column in row 1; so why wouldn't you return 7 for row 3??)
Try this:
sizeA = size(A);
N = sizeA(1);
D = diff([zeros(1, N); (A.' ~= 0); zeros(1,N)]) ~= 0;
[a b] = find(D ~= 0);
c = reshape(a, 2, []);
midRow = floor(sum(c)/2);
midCol = b(1:2:length(b))
After this, midRow and midCol contain the indices of your centroids (e.g. midRow(1) = 1, midCol(1) = 4 for the example matrix you gave above.
If you don't mind using a for loop:
A = [ 0 0 1 1 1 0 1;
0 0 0 0 0 0 0;
0 1 1 1 1 0 0;
0 1 1 1 0 1 1;
0 0 0 0 1 0 0]; % data
sol = repmat(NaN,size(A,1),1);
for row = 1:size(A,1)
[aux_row aux_col aux_val] = find(A(row,:));
if ~isempty(aux_col)
sol(row) = aux_col(1) + floor((find(diff([aux_col 0])~=1,1)-1)/2);
% the final 0 is necessary in case the row of A ends with ones
% you can use either "floor" or "ceil"
end
end
disp(sol)
Try it and see if it does what you want. I hope the code is clear; if not, tell me