How to make a for loop stop after a set number of iterations in Julia - for-loop

I am still pretty new at programming and I would appreciate any help on how to approach the following problem:
Given a matrix (3x5)
a = [1 2 3 4 5;
6 7 8 9 10;
11 12 13 14 15;]
I want to iterate through every row
For each row, I want each element to be checked
With each element, I want to store a separate array that holds the element and the next 2 elements.
Ex:
Row 1 = [1 2 3 4 5]
For element 1
return newArray = [1 2 3]
For element 2
return newArray = [2 3 4]
Getting stuck on part 3. How to make the for loop check only up to the next 2 elements and then continue to the next element in the row.

I took a shot at solving what you asked for, but I agree with the others that you need to think more about what you are trying to do and what you want your output to look like. Your request does not sound like something a beginner programmer would realistically use. I am not sure what shape you want to store your "separate array"s in. I have options below for keeping them in a vector or in the original shape of a.
function nexttwo(row, i)
newarray::Vector{Any} = [row[i]]
for j=1:2
i+=1
if length(row) >= i
push!(newarray, row[i])
else
push!(newarray, nothing)
end
end
return newarray
end
function collectnexttwo(a)
result_collection = []
for i in axes(a,1)
for j in axes(a,2)
row = a[i,:]
newarray = nexttwo(row, j)
push!(result_collection, newarray)
end
end
return result_collection
end
function restoreshape(v, a)
permutedims(reshape(v, reverse(size(a))))
end
julia> a = [1 2 3 4 5; 6 7 8 9 10; 11 12 13 14 15;]
3×5 Matrix{Int64}:
1 2 3 4 5
6 7 8 9 10
11 12 13 14 15
julia> result = restoreshape(collectnexttwo(a), a)
3×5 Matrix{Any}:
Any[1, 2, 3] Any[2, 3, 4] Any[3, 4, 5] Any[4, 5, nothing] Any[5, nothing, nothing]
Any[6, 7, 8] Any[7, 8, 9] Any[8, 9, 10] Any[9, 10, nothing] Any[10, nothing, nothing]
Any[11, 12, 13] Any[12, 13, 14] Any[13, 14, 15] Any[14, 15, nothing] Any[15, nothing, nothing]

I think that you have some problems with the statement of what you want to achieve. That can often make a programming assignment much harder.
Restating what you have already:
I want to iterate through every row
This is pretty easy
for row = 1:size(a)[1]
...
end
For each row, I want each element to be checked
This is where things begin to get squishy? What do you mean by "checked". Let's assume you have some function called checkElement.
With each element, I want to store a separate array that holds the element and the next 2 elements.
How long do you want that separate array to live? Do you just want to hold 3 elements? Or three elements for every cell of the original (i.e. have a 3x5x3 result for a 3x5 input like you show)
Also, what do you want to do about elements 4 and 5 in each row? What values do you want to use for their "next" elements? You could use missing as a value or NaN. Or you could make the result just not contain the problematic inputs.
If you answer these questions, you are likely to find it much easier to write the code you need.

Related

Neighbors in the matrix - algorithm

I have a problem with coming up with an algorithm for the "graph" :(
Maybe one of you would be so kind and direct me somehow <3
The task is as follows:
We have a board of at least 3x3 (it doesn't have to be a square, it can be 4x5 for example). The user specifies a sequence of moves (as in Android lock pattern). The task is to check how many points he has given are adjacent to each other horizontally or vertically.
Here is an example:
Matrix:
1 2 3 4
5 6 7 8
9 10 11 12
The user entered the code: 10,6,7,3
The algorithm should return the number 3 because:
10 is a neighbor of 6
6 is a neighbor of 7
7 is a neighbor of 3
Eventually return 3
Second example:
Matrix:
1 2 3
4 5 6
7 8 9
The user entered the code: 7,8,6,3
The algorithm should return 2 because:
7 is a neighbor of 8
8 is not a neighbor of 6
6 is a neighbor of 3
Eventually return 2
Ofc number of operations equal length of array - 1
Sorry for "ile" and "tutaj", i'm polish
If all the codes are unique, use them as keys to a dictionary (with (row/col) pairs as values). Loop thru the 2nd item in user input to the end, check if math.Abs(cur.row-prev.row)+math.Abs(cur.col-prev.col)==1. This is not space efficient but deal with user input in linear complexity.
The idea is you have 4 conditions, one for each direction. Given any matrix of the shape n,m which is made of a sequence of integers AND given any element:
The element left or right will always be + or - 1 to the given element.
The element up or down will always be + or - m to the given element.
So, if abs(x-y) is 1 or m, then x and y are neighbors.
I demonstrate this in python.
def get_neighbors(seq,matrix):
#Conditions
check = lambda x,y,m: np.abs(x-y)==1 or np.abs(x-y)==m
#Pairs of sequences appended with m
params = zip(seq, seq[1:], [matrix.shape[1]]*(len(seq)-1))
neighbours = [check(*i) for i in params]
count = sum(neighbours)
return neighbours, count
seq = [7,8,6,3]
matrix = np.arange(1,10).reshape((3,3))
neighbours, count = get_neighbors(seq, matrix)
print('Matrix:')
print(matrix)
print('')
print('Sequence:', seq)
print('')
print('Count of neighbors:',count)
Matrix:
[[ 1 2 3 4]
[ 5 6 7 8]
[ 9 10 11 12]]
Sequence: [10, 6, 7, 3]
Count of neighbors: 3
Another example -
seq = [7,8,6,3]
matrix = np.arange(1,10).reshape((3,3))
neighbours, count = get_neighbors(seq, matrix)
Matrix:
[[1 2 3]
[4 5 6]
[7 8 9]]
Sequence: [7, 8, 6, 3]
Count of neighbors: 2
So your input is the width of a table, the height of a table, and a list of numbers.
W = 4, H = 3, list = [10,6,7,3]
There are two steps:
Convert the list of numbers into a list of row/column coordinates (1 to [1,1], 5 to [2,1], 12 to [3,4]).
In the new list of coordinates, find consequent pairs, which have one coordinate identical, and the other one has a difference of 1.
Both steps are quite simple ("for" loops). Do you have problems with 1 or 2?

How to find smallest number of lists needed to cover all elements in another list

I'm working on a code using Matlab in which I need to find the least number lists (in some set of given lists) necessary to cover all the elements of a reference list.
For example, say my reference list is
X = [0 1 2 3 4 5 6 7 8 9]
And I have a given set of lists as follows:
A = [0 1 3 5 6 7 9]
B = [0 1 2 3 4]
C = [5 6 7 8 9]
D = [1 2 3 4]
E = [1 5 7 8]
The smallest number of lists needed to cover every element in X is 2 (B and C), however, if I initially only search for the list that covers the most elements (A) and then try to find other lists that will cover the remaining elements, I'll end up using at least 3 lists. What would be the best way to write a code that can search for the smallest number of lists necessary for this (it would give me an output of B and C)? Any help at all would be greatly appreciated...even just a conceptual explanation (not actual code) of how to best approach this problem would be a huge help!
Approach #1: Iterative "brute-force" of all possible combinations
Below is one possible algorithm that illustrates how to solve the problem. The code itself should be self-explanatory, but the idea is that we test all possible combinations of lists until a valid one is found (hence we don't encounter the problem you described where we mistakenly choose lists based on their length).
function varargout = q36323802
R = [0 1 2 3 4 5 6 7 8 9]; %// Reference List
L = {... // As per Dan's suggestion:
[0 1 3 5 6 7 9]
[0 1 2 3 4]
[5 6 7 8 9]
[1 2 3 4]
[1 5 7 8]
};
out = []; %// Initialize output
%% // Brute-force approach:
nLists = numel(L);
for indN = 1:nLists
setCombinationsToCheck = nchoosek(1:nLists,indN);
for indC = 1:size(setCombinationsToCheck,1)
u = unique(cat(2,L{setCombinationsToCheck(indC,:)}));
if all(ismember(R,u))
out = setCombinationsToCheck(indC,:);
disp(['The minimum number of required sets is ' num2str(indN) ...
', and their indices are: ' num2str(out)]);
return;
end
end
end
disp('No amount of lists found to cover the reference.');
if nargout > 0
varargout{1} = out;
end
For your example the output is:
The minimum number of required sets is 2, and their indices are: 2 3
Note(s):
This method does some redundant computations by not using lists of length n-1 in iteration n, which were already found in previous iterations (when applicable). A recursive solution may work in this case.
There is probably a way to vectorize this, which I did not really think about in depth.
I assumed all inputs are row vectors. There would have to be some extra steps if this is not the case.
Thanks go to Adiel for suggesting some improvements, and for Amro for finding some bugs!
Approach #2: Tree search Experimental
I've attempted to also build a recursive solver. Now it finds a solution, but it's not general enough (actually the problem is that it only returns the first result, not necessarily the best result). The reasoning behind this approach is that we can treat your question as a tree search problem, and so we can employ search/pathfinding algorithms (see BFS, DFS, IDS etc.). I think the algorithm below is closest to DFS. As before, this should mainly illustrate an approach to solving your problem.
function q36323802_DFS(R,L)
%% //Input checking:
if nargin < 2 || isempty(L)
L = {... // As per Dan's suggestion:
[0 1 3 5 6 7 9]
[0 1 2 3 4]
[5 6 7 8 9]
[1 2 3 4]
[1 5 7 8]
};
end
if nargin < 1 || isempty(R)
R = [0 1 2 3 4 5 6 7 8 9]; %// Reference List
end
%% // Algorithm (DFS: breadth-first search):
out = DFS_search(R,L,0);
if isempty(out)
disp('No amount of lists found to cover the reference.');
else
disp(['The minimum number of required sets is ' num2str(numel(out)) ...
', and their indices are: ' num2str(out)]);
end
end
function out = DFS_search(R,L,depth)
%// Check to see if we should stop:
if isempty(R) || isempty(L)
% // Backtrack here?
out = [];
return;
end
if isnan(R)
out = [];
return;
end
nLists = numel(L);
reducedR = cellfun(#(R,L)setdiff(R,L),repmat({R},[nLists,1]),L,'UniformOutput',false)';
%'// We consider a case where the reduction had no effect as "hopeless" and
%// "drop" it.
isFullCoverage = cellfun(#isempty,reducedR);
isHopeless = cellfun(#(R)all(isnan(R)),reducedR) | cellfun(#(rR)isequal(rR,R),reducedR);
reducedR(isHopeless) = deal({NaN});
if all(isHopeless) && ~any(isFullCoverage)
out = [];
return
end
if any(isFullCoverage) %// Check current "breadth level"
out = find(isFullCoverage,1,'first');
return
else
for indB = 1:nLists
out = DFS_search(reducedR{indB},L,depth+1);
if ~isempty(out)
out = [indB out]; %#ok
%// TODO: test if one of the sets is covered by the others and remove it
%// from the list "out".
%// Also, keep track of the best path and only return (finally) if shortest
return
end
end
end
end
A similar solution to Dev-iL's 1st approach, by Amro:
function varargout = q36323802A
R = [0 1 2 3 4 5 6 7 8 9];
names = {'A' 'B' 'C' 'D' 'E'};
L = {...
[0 1 3 5 6 7 9]
[0 1 2 3 4]
[5 6 7 8 9]
[1 2 3 4]
[1 5 7 8]
};
N = numel(L);
%// powerset of L: set of all subsets (excluding empty set)
powerset = cell(1,N);
for k=1:N
sets = nchoosek(1:N, k);
powerset{k} = num2cell(sets,2);
end
powerset = cat(1, powerset{:});
%// for each possible subset, check if it covers the target R
mask = false(size(powerset));
for i=1:numel(powerset)
elems = unique([L{powerset{i}}]);
mask(i) = all(ismember(R, elems));
end
if ~any(mask), error('cant cover target'); end
%// from candidates, choose the one with least amount of sets
candidates = powerset(mask);
len = cellfun(#numel, candidates);
[~,idx] = min(len);
out = candidates{idx};
varargout{1} = names(out);

Replace multiple pixels value in an image with a certain value Matlab

I have an image 640x480 img, and I want to replace pixels having values not in this list or array x=[1, 2, 3, 4, 5] with a certain value 10, so that any pixel in img which doesn't have the any of the values in x will be replaced with 10. I already know how to replace only one value using img(img~=1)=10 or multiple values using this img(img~=1 & img~=2 & img~=3 & img~=4 & img~=5)=10 but I when I tried this img(img~=x)=10 it gave an error saying Matrix dimensions must agree. So if anyone could please advise.
You can achieve this very easily with a combination of permute and bsxfun. We can create a 3D column vector that consists of the elements of [1,2,3,4,5], then use bsxfun with the not equals method (#ne) on your image (assuming grayscale) so that we thus create a 3D matrix of 5 slices. Each slice would tell you whether the locations in the image do not match an element in x. The first slice would give you the locations that don't match x = 1, the second slice would give you the locations that don't match x = 2, and so on.
Once you finish this, we can use an all call operating on the third dimension to consolidate the pixel locations that are not equal to all of 1, 2, 3, 4 or 5. The last step would be to take this logical map, which that tells you the locations that are none of 1, 2, 3, 4, or 5 and we'd set those locations to 10.
One thing we need to consider is that the image type and the vector x must be the same type. We can ensure this by casting the vector to be the same class as img.
As such, do something like this:
x = permute([1 2 3 4 5], [3 1 2]);
vals = bsxfun(#ne, img, cast(x, class(img)));
ind = all(vals, 3);
img(ind) = 10;
The advantage of the above method is that the list you want to use to check for the elements can be whatever you want. It prevents having messy logical indexing syntax, like img(img ~= 1 & img ~= 2 & ....). All you have to do is change the input list at the beginning line of the code, and bsxfun, permute and any should do the work for you.
Here's an example 5 x 5 image:
>> rng(123123);
>> img = randi(7, 5, 5)
img =
3 4 3 6 5
7 2 6 5 1
3 1 6 1 7
6 4 4 3 3
6 2 4 1 3
By using the code above, the output we get is:
img =
3 4 3 10 5
10 2 10 5 1
3 1 10 1 10
10 4 4 3 3
10 2 4 1 3
You can most certainly see that those elements that are neither 1, 2, 3, 4 or 5 get set to 10.
Aside
If you don't like the permute and bsxfun approach, one way would be to have a for loop and with an initially all true array, keep logical ANDing the final result with a logical map that consists of those locations which are not equal to each value in x. In the end, we will have a logical map where true are those locations that are neither equal to 1, 2, 3, 4 or 5.
Therefore, do something like this:
ind = true(size(img));
for idx = 1 : 5
ind = ind & img ~= idx;
end
img(ind) = 10;
If you do this instead, you'll see that we get the same answer.
Approach #1
You can use ismember,
which according to its official documentation for a case of ismember(A,B) would output a logical array of the same size as A and with 1's where
any element from B is present in A, 0's otherwise. Since, you are looking to detect "not in the list or array", you need to invert it afterwards, i.e. ~ismember().
In your case, you have img as A and x as B, so ~ismember(img,x) would give you those places where img~=any element in x
You can then map into img to set all those in it to 10 with this final solution -
img(~ismember(img,x)) = 10
Approach #2
Similar to rayryeng's solution, you can use bsxfun, but keep it in 2D which could be more efficient as it would also avoid permute. The implementation would look something like this -
img(reshape(all(bsxfun(#ne,img(:),x(:).'),2),size(img))) = 10

cut signal (interlinked) and compute theses parts

I'm a French student engineer in signal processing field and I do my internship in a neuroscience laboratory. I've to process a lot of data from the brain activity with the help of Matlab, so one of my main subject is to optimize the code. But now I'm stuck in a situation that I can't resolve and I don't find anything about it on the web. I explain my problem :
For example the matrix a :
a = [ 1 2 3 4 5; 6 7 8 9 10;11 12 13 14 15]
Each row is the datas of a signal (so here we have 3 signals), and I want, for each signal/row, cut the vector in blcoks interlinked of the same length.
For instance for the signal 1, S1 = [1 2 3 4 5] I want to extract the bloc S1_1 = [1 2 3], S1_2 = [2 3 4], and S1_3 = [3 4 5] and compute every sub-block.
My first idea was to use nested loop like that :
[nrow ncol] = size(a);
for i = 1 : nrow
for j = 4 : ncol
sub_block = a(i, (j-3):j);
result(i, j-3) = compute(sub_block);
end
end
BUT as I said I have to process a lot of datas, so I want to avoid for-loop. I'm looking for an algorithm wich will be able to remove these for-loop but I don't know how to do...
I saw the function 'reshape' but this on give me sub-block like : S1_1 = [1 2 3], S1_2 = [4 5 6] I can't use it because here in the sub-block S1_2 I have the data from the signal 1 and the signal 2.
Then I saw the function 'blockproc' but I didn't really understand how it process and I'm not really convaince that this one can help me...
So, I hope you understand my problem and that you could help me or indicate me a way to find a solution.
In addition to #Ziyao Wei's suggestion you could alternatively use im2col:
>> S = im2col(a', [3 1])
S =
1 2 3 6 7 8 11 12 13
2 3 4 7 8 9 12 13 14
3 4 5 8 9 10 13 14 15
Where S(:, 3*k-2:3*k) for k = 1:data_rows are the desired sub-blocks of row k of your data (a).
Blockproc seems to be doing a block operation rather than a sliding operation. A bit of digging around gives this:
http://www.mathworks.com/help/images/ref/nlfilter.html
But it seems the image processing toolbox is needed.
Also this might help:
http://dovgalecs.com/blog/matlab-sliding-window-easy-and-painless/
In general, try to search for sliding-window or convolution, and try to see if something shows up.
You could probably find another way of doing your loop with the arrayfun function, but the fact is that it might not necessarily be faster arrayfun can be significantly slower than an explicit loop in matlab. Why?
Thank you a lot for all your (quick) answers ! I didn't expect to get an answer so quickly !
I have the image processing toolbox and your different methods are greats ! I'll have to use the im2col because is the "slower" solution for me and I can remove one for-loop.
Thank you for your help

Divide Set of numbers to sequence? Find General Term?

How can we divide set of numbers to sequence? And find the general term?
1 - numbers are always in order
2 - if we have n numbers n/2 numbers are always present
For example we have:
Input: 0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30
Output--> 2*X, x=[0..15]
OR
Input: 0,2,4,5,6,8,10,12,14,15,16,18,20,22,24,26,28,30
Divide into two set
A: 0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30
B: 5,10,15,20
Output--> 2*X, x=[0..15] AND 5*X, x=[1..4]
I think this is very difficult, any comments?
What computer field or algorithm can help me?
The problem as I understand it is this: Given a sequence of numbers, find the set of sequences that start from zero and increase by a constant multiple which cover this set.
Here's a general outline of what I would do:
I would make a list of all the numbers in the set, and iterate through starting from the first two elements to generate all of the possible sets meeting your criteria which are here. If you encounter an element in the list, you can remove it from consideration as a generating number since any list with that number as a constant multiple is a subset of a list you've encountered before. When you are done you will have a list of possible sets you can use to cover that set. FOR EXAMPLE:
0,2,4,5,6,8,10,12,14,15,16,18,20,22,24,26,28,30
We will start with 0 and 2. We'll look for elements that are successively 2 larger and remove them from the list of elements that will be considered as possible multiples. Once we find a multiple of 2 that's not in this list, we'll stop generating. Here we go:
s(2) = [0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30]
Which leaves:
[5,15]
as the two potential other candidates. Do you see that any of the elements, eg, 4, which are divisible by two will make subsets of that list and thus don't need to be considered?
The remaining list in the set will start at 0 and increase by 5, our smallest element:
[0,5,10,15,20]
(Remember we are checking the original list for these multiples and not the truncated list- the truncated list is only the list of remaining candidates. When the candidate list is empty we know we will have found all of the sets which are contained in this set who have no supersets.
For a more complex example:
[0 2 3 4 5 6 7 8 9 10 12 13 14 15]
We'll start with:
[0 2 4 6 8 10 12 14]
Which leaves
[3 5 7 9 13 15]
as candidates, which in turn generates:
[0 3 6 9 12 15]
which leaves
[5 7 13]
which generates
[0 5 10 15]
which leaves
[7 13]
which generates
[0 7 14]
which leaves
[13]
which generates
[0 13].
The total combination of sets is:
[0 2 4 6 8 10 12 14]
[0 3 6 9 12 15]
[0 5 10 15]
[0 7 14]
[0 13].
At this point, you have the smallest list of all of the sets needed to cover your set. It should be trivial to generate the proper [0,1...n]/a*n descriptors from here.

Resources