I'm trying to generate a list in NetLogo that contains several different unique lists of 0 and 1. The number of 1s depends j and the number of lists depends on i. For example, I have these lines of code:
if (i = 4) and (j=1) [set mylist = [[1 0 0 0][0 1 0 0][0 0 1 0][0 0 0 1]]]
if (i = 4) and (j=2) [set mylist = [[1 1 0 0][1 0 1 0][1 0 0 1][0 1 1 0][0 1 0 1] [0 0 1 1]]]
that I wrote to make all possible unique combinations of 0 and 1 without any repetitions within the lists. I would like to be able to the same thing but for values of both i and j, ranging from 1-10. Is there an example of how to do this, or some sort of pseudocode algorithm that anyone knows of that I could check out? Thanks!
to-report combinations [_m _s]
if (_m = 0) [ report [[]] ]
if (_s = []) [ report [] ]
let _rest butfirst _s
let _lista map [? -> fput item 0 _s ?] combinations (_m - 1) _rest
let _listb combinations _m _rest
report (sentence _lista _listb)
end
;convert location list to bitstring
to-report bitstring [#len #locs]
report map [? -> ifelse-value (member? ? #locs) [1] [0]] range #len
end
;try it out:
to-report test-values [#i #j] ;e.g., test-values 4 2
report map [? -> bitstring #i ?] combinations #j range #i
end
Related
Consider the following data:
A = [-1 -1 -1 0 1 -1 -1 0 0 1 1 1 1 -1 1 0 1];
How can the size and appearance frequency of clusters in A (of similar neighbors) be calculated, preferably using MATLAB built in commands?
The result should read something like
s_plus = [1 2 3 4 5 ; 3 0 0 1 0]'; % accounts (1,1,1,1) and (1),(1),(1) which appear in A
s_zero = [1 2 3 4 5 ; 2 1 0 0 0]'; % accounts (0,0) and (0),(0) which appear in A
s_mins = [1 2 3 4 5 ; 1 1 1 0 0]'; % accounts (-1), (-1,-1) , and (-1,-1,-1)) which appear in A
in the above the first column indicates the cluster size and the second column is the appearance frequency.
You can use run length encoding to transform your input array into two arrays
The value of a group (or "run" of equal values)
The number of elements in that group
Then you can covert this into your desired output by checking when two conditions are true
The values array matches the value you want (-1,0,1)
The group size matches 1..5
This might sound a bit tricky but it's only a few lines of code, and should be relatively fast for even large arrays because the outputs are calculated from the "encoded" arrays which will be smaller than the input array.
Here is the code, see the comments for details:
A = [-1 -1 -1 0 1 -1 -1 0 0 1 1 1 1 -1 1 0 1]; % Example input
% Run length encoding step
idx = [ find( A(1:end-1) ~= A(2:end) ), numel(A) ]; % Find group start points
count = diff([0, idx]); % Find number of elements in each group
val = A( idx ); % Get value of each group
% Helper function to go from "val" and "count" to desired output format
% by checking value = target and group size matches 1 to 5, counting matching groups.
f = #(v) sum(val==v & count==(1:5).',2).';
% Create outputs
s_plus = f(1); % = [3 0 0 1 0]
s_zero = f(0); % = [2 1 0 0 0]
s_mins = f(-1); % = [1 1 1 0 0]
I've got logical array(zeros and ones) 1500x700
I want to find "1" in every column and when there are more than one "1" in column i should choose the middle one.
Is that possible to do it? I know how to find "1", but don't know how to extract the middle "1" if there's couple of "1" in one column.
The find function returns the indices of your ones.
>> example=[1,0,0,1,0,1,1];
>> indices=find(example)
indices =
1 4 6 7
>> indices(floor(numel(indices)/2))
ans =
4
Do this for each column and you have a solution.
You can
Get the row and column indices of ones with find;
Apply accumarray with a custom function to get the middle row index for each column.
x = [1 0 0 0 0; 0 0 1 0 0; 1 0 1 0 0; 1 0 0 1 0]; % example
[ii, jj] = find(x); % step 1
result = accumarray(jj, ii, [size(x,2) 1], #(x) x(ceil(end/2)), NaN); % step 2
Note that:
For an even number of ones this gives the first of the two middle indices. If you prefer the average of the two middle indices replace #(x) x(ceil(end/2)) by #median.
For a column without ones this gives NaN as result. If you prefer a different value, replace the input fifth argument of accumarray by that.
Example:
x =
1 0 0 0 0
0 0 1 0 0
1 0 1 0 0
1 0 0 1 0
result =
3
NaN
2
4
NaN
I have vector of all edges for example
A = [1;2;3;4];
I also have the matrix of all the links connecting these edges represented by the edge numbers for example
B = [1 3;3 1;1 2;1 2;2 3;4 3];
I would like to construct the adjacency matrix with this data. The matrix should not consider the ordering of the edges in the links For example the second link has edges 1 2 but the matrix should have entries in both 1,2 and 2,1.
So therefore i need an output like this
C = [0 1 1 0;1 0 1 0;1 1 0 1;0 0 1 0];
I cannot think of any other way other than using a for loop for the size of B and then finding the egdes for each link in B and then adding 1's to a pre-initialized 4x4 matrix at i,j where i,j is the link edges.
Is this an efficient way because my real size is many magnitudes greater than 4? Could someone help with a better way to construct the matrix?
You can use sparse to build the matrix, and then optionally convert to full:
result = full(sparse(B(:,1), B(:,2), 1)); % accumulate values
result = result | result.'; % make symmetric with 0/1 values
Equivalently, you can use accumarray:
result = accumarray(B, 1); % accumulate values
result = result | result.'; % make symmetric with 0/1 values
For A = [1;2;3;4]; B = [1 3;3 1;1 2;1 2;2 3;4 3], either of the above gives
result =
4×4 logical array
0 1 1 0
1 0 1 0
1 1 0 1
0 0 1 0
I want to find the lengths of all series of ones and zeros in a logical array in MATLAB. This is what I did:
A = logical([0 0 0 1 1 1 1 0 1 1 0 0 0 0 0 0 1 1 1 1 1]);
%// Find series of ones:
csA = cumsum(A);
csOnes = csA(diff([A 0]) == -1);
seriesOnes = [csOnes(1) diff(csOnes)];
%// Find series of zeros (same way, using ~A)
csNegA = sumsum(~A);
csZeros = csNegA(diff([~A 0]) == -1);
seriesZeros = [csZeros(1) diff(csZeros)];
This works, and gives seriesOnes = [4 2 5] and seriesZeros = [3 1 6]. However it is rather ugly in my opinion.
I want to know if there is a better way to do this. Performance is not an issue as this is inexpensive (A is no longer than a few thousand elements). I am looking for code clarity and elegance.
If nothing better can be done, I'll just put this in a little helper function so I don't have to look at it.
You could use an existing code for run-length-encoding, which does the (ugly) work for you and then filter out your vectors yourself. This way your helper function is rather general and its functionality is evident from the name runLengthEncode.
Reusing code from this answer:
function [lengths, values] = runLengthEncode(data)
startPos = find(diff([data(1)-1, data]));
lengths = diff([startPos, numel(data)+1]);
values = data(startPos);
You would then filter out your vectors using:
A = logical([0 0 0 1 1 1 1 0 1 1 0 0 0 0 0 0 1 1 1 1 1]);
[lengths, values] = runLengthEncode(A);
seriesOnes = lengths(values==1);
seriesZeros = lengths(values==0);
You can try this:
A = logical([0 0 0 1 1 1 1 0 1 1 0 0 0 0 0 0 1 1 1 1 1]);
B = [~A(1) A ~A(end)]; %// Add edges at start/end
edges_indexes = find(diff(B)); %// find edges
lengths = diff(edges_indexes); %// length between edges
%// Separate zeros and ones, to a cell array
s(1+A(1)) = {lengths(1:2:end)};
s(1+~A(1)) = {lengths(2:2:end)};
This strfind (works wonderfully with numeric arrays as well as string arrays) based approach could be easier to follow -
%// Find start and stop indices for ones and zeros with strfind by using
%// "opposite (0 for 1 and 1 for 0) sentients"
start_ones = strfind([0 A],[0 1]) %// 0 is the sentient here and so on
start_zeros = strfind([1 A],[1 0])
stop_ones = strfind([A 0],[1 0])
stop_zeros = strfind([A 1],[0 1])
%// Get lengths of islands of ones and zeros using those start-stop indices
length_ones = stop_ones - start_ones + 1
length_zeros = stop_zeros - start_zeros + 1
I have a Vector 1xm, ShortMemory (SM), and a Matrix nxm, Agenda (AG).
SM only have positive integers and zeros.
Each column of AG only has one element equal to 1 and all the other elements of the same column equal to 0.
My objective is changing the position of the number 1 from a randomly choosen column from AG. The problem is that only columns that have a corresponding 0 in SM can be changed.
Example:
SM = [1 0 2];
AG = [1 1 0 ; 0 0 1 ; 0 0 0];
Randomly Generated number here
RandomColumn = 2;
The possible outcomes would be
AG = [1 0 0 ; 0 1 1 ; 0 0 0]; or AG = [1 0 0; 0 0 1 ; 0 1 0]; or AG = [1 1 0 ; 0 0 1 ; 0 0 0];
The Line that gets the 1 is also random but that's easy to do
I could do it by just getting random numbers between 1 and m but m can be very big in my problem and the number of zeros can be very small too, so it could potentially take alot of time. I could also do it with a cycle but it's Matlab and this is embeded on double cycle already.
Thanks
edit: Added commentary to the code for clarity.
edit: Corrected an error on possible outcome
My solution is based on following assumptions:
Objective is changing the position of the number 1 from a randomly choosen column from AG.
Only columns that have a corresponding 0 in SM can be changed.
Solution:
% input
SM = [1 0 2]
AG = [1 1 0 ; 0 0 1 ; 0 0 0]
% generating random column according to assumptions 1 and 2
RandomColumn1 = 1:size(AG,2);
RandomColumn1(SM~=0)=[];
RandomColumn1=RandomColumn1(randperm(length(RandomColumn1)));
RandomColumn=RandomColumn1(1);
% storing the current randomly chosen column before changing
tempColumn=AG(:,RandomColumn);
% shuffling the position of 1
AG(:,RandomColumn)=AG(randperm(size(AG,1)),RandomColumn);
% following checks if the column has remained same after shuffling. This while loop should execute (extremely) rarely.
while tempColumn==AG(:,RandomColumn)
tempColumn=AG(:,RandomColumn);
AG(:,RandomColumn)=AG(randperm(size(AG,1)),RandomColumn);
end
AG