How to oppositely order two vectors in Matlab? - matlab

I have the code below for oppositely ordering two vectors. It works, but I want to specify the line
B_diff(i) = B(i) - B(i+1);
to hold true not just for only
B_diff(i) = B(i) - B(i+1); but for
B_diff(i) = B(i) - B(i+k); where k can be any integer less than or equal to n. The same applies to "A". Any clues as to how I can achieve this in the program?
For example, I want to rearrange the first column of the matrix
A =
1 4
6 9
3 8
4 2
such that, the condition should hold true not only for
(a11-a12)(a21-a22)<=0;
but also for all
(a11-a13)(a21-a23)<=0;
(a11-a14)(a21-a24)<=0;
(a12-a13)(a22-a23)<=0;
(a12-a14)(a22-a24)<=0; and
(a13-a14)(a23-a24)<=0;
## MATLAB CODE ##
A = xlsread('column 1');
B = xlsread('column 2');
n = numel(A);
B_diff = zeros(n-1,1); %Vector to contain the differences between the elements of B
count_pos = 0; %To count the number of positive entries in B_diff
for i = 1:n-1
B_diff(i) = B(i) - B(i+1);
if B_diff(i) > 0
count_pos = count_pos + 1;
end
end
A_desc = sort(A,'descend'); %Sort the vector A in descending order
if count_pos > 0 %If B_diff contains positive entries, divide A_desc into two vectors
A_less = A_desc(count_pos+1:n);
A_great = sort(A_desc(1:count_pos),'ascend');
A_new = zeros(n,1); %To contain the sorted elements of A
else
A_new = A_desc; %This is then the sorted elements of A
end
if count_pos > 0
A_new(1) = A_less(1);
j = 2; %To keep track of the index for A_less
k = 1; %To keep track of the index for A_great
for i = 1:n-1
if B_diff(i) <= 0
A_new(i+1) = A_less(j);
j = j + 1;
else
A_new(i+1) = A_great(k);
k = k + 1;
end
end
end
A_diff = zeros(n-1,1);
for i = 1:n-1
A_diff(i) = A_new(i) - A_new(i+1);
end
diff = [A_diff B_diff]
prod = A_diff.*B_diff

The following code orders the first column of A opposite to the order of the second column.
A= [1 4; 6 9; 3 8; 4 2]; % sample matrix
[~,ix]=sort(A(:,2)); % ix is the sorting permutation of A(:,2)
inverse=zeros(size(ix));
inverse(ix) = numel(ix):-1:1; % the un-sorting permutation, reversed
B = sort(A(:,1)); % sort the first column
A(:,1)=B(inverse); % permute the first column according to inverse
Result:
A =
4 4
1 9
3 8
6 2

Related

How to determine number of hops using a vector?

I have a MATLAB matrix like below:
column no: 1 2 3 4 5 6
matrix elements 1 1 2 3 6 2
Column numbers represent node ID and elements of the matrix represent the node towards which that node points. Please help me find hop count from a particular node to node 1. I have written the following code but it doesn't solve the problem.
x = ones(1, n);
checkbit = zeros(1, n);
nodedest = [1 1 2 3 6 2];
hopcount = zeros(1, n);
for i = 1:n
for j = 1:n
if nodedest(j) == 1 && checkbit(j) == 0
hopcount(j) = hopcount(j) + 1;
checkbit(j) = 1;
else
x(j) = nodedest(j);
end
if x(j) ~= 1
hopcount(j) = hopcount(j) + 1;
x(j) = nodedest(x(j));
end
end
end
You are looking for a breadth-first search to find the shortest path in your graph. Without touching the data in any way, you can do this in O(n) time per node, given the tree-like structure of your graph:
nodedest = [1 1 2 3 6 2];
hopcount = zeros(1, 6);
for n = 2:6
k = n
while k ~= 1
hopcount(n) = hopcount(n) + 1
k = nodedest(k)
end
end
If you are willing to reverse the sense of your edges (introducing a one-to-many relationship), you could accomplish the same thing in one pass, reducing the entire algorithm from O(n2) to O(n) time complexity. The trade-off would be that memory complexity would increase from O(1) to O(n):
nodedest = [1 1 2 3 6 2];
% Reverse the input
nodesource = cell(1, 6);
nodesource(:) = {[]}
for n = 2:6
k = nodedest(n);
nodesource{k} = [nodesource{k} n];
end
% implement bfs, using the assumption that the graph is a simple tree
hopcount = zeros(1, 6);
cache = [1];
hops = 0;
while ~isempty(cache)
next = []
for c = cache
hopcount(c) = hops;
next = [next nodesource(c)]
end
hops = hops + 1;
cache = next
end

How can I do vectorization for this matlab "for loop"?

I have some matlab code as follow, constructing KNN similarity weight matrix.
[D,I] = pdist2(X, X, 'squaredeuclidean', 'Smallest', k+1);
D = D < threshold;
W = zeros(n, n);
for i=1:size(I,2)
W(I(:,i), i) = D(:,i);
W(i, I(:,i)) = D(:,i)';
end
I want to vectorize the for loop. I have tried
W(I) = D;
but failed to get the correct value.
I add test case here:
n = 5;
D = [
1 1 1 1 1
0 1 1 1 1
0 0 0 0 0
];
I = [
1 2 3 4 5
5 4 5 2 3
3 1 1 1 1
];
There are some undefined variables that makes it hard to check what it is doing, but this should do the same as your for loop:
D,I] = pdist2(X, X, 'squaredeuclidean', 'Smallest', k+1);
D = D < threshold;
W = zeros(n);
% set the diagonal values
W(sub2ind(size(X), I(1, :), I(1, :))) = D(1,:);
% set the other values
W(sub2ind(size(W), I(2, :), 1:size(I, 2))) = D(2, :);
W(sub2ind(size(W), 1:size(I, 2), I(2, :))) = D(2, :).';
I splited the directions, it works now with your test case.
A possible solution:
idx1 = reshape(1:n*n,n,n).';
idx2 = bsxfun(#plus,I,0:n:n*size(I,2)-1);
W=zeros(n,n);
W(idx2) = D;
W(idx1(idx2)) = D;
Here assumed that you repeatedly want to compute D and I so compute idx only one time and use it repeatedly.
n = 5;
idx1 = reshape(1:n*n,n,n).';
%for k = 1 : 1000
%[D,I] = pdist2(X, X, 'squaredeuclidean', 'Smallest', k+1);
%D = D < threshold;
idx2 = bsxfun(#plus,I,0:n:n*size(I,2)-1);
W=zeros(n,n);
W(idx2) = D;
W(idx1(idx2)) = D;
%end
But if n isn't constant and it varies in each iteration it is better to change the way idx1 is computed:
n = 5;
%for k = 1 : 1000
%n = randi([2 10]);%n isn't constant
%[D,I] = pdist2(X, X, 'squaredeuclidean', 'Smallest', k+1);
%D = D < threshold;
idx1 = bsxfun(#plus,(0:n:n^2-1).',1:size(I,2));
idx2 = bsxfun(#plus,I,0:n:n*size(I,2)-1);
W=zeros(n,n);
W(idx2) = D;
W(idx1(idx2)) = D;
%end
You can cut some corners with linear indices but if your matrices are big then you should only take the nonzero components of D. Following copies all values of D
W = zeros(n);
W(reshape(sub2ind([n,n],I,[1;1;1]*[1:n]),1,[])) = reshape(D,1,[]);

Vectorization in Matlab to speed up expensive loop

How can I speed up the following MATLAB code, using vectorization? Right now the single line in the loop is taking hours to run for the case upper = 1e7.
Here is the commented code with sample output:
p = 8;
lower = 1;
upper = 1e1;
n = setdiff(lower:upper,primes(upper)); % contains composite numbers between lower + upper
x = ones(length(n),p); % Preallocated 2-D array of ones
% This loop stores the unique prime factors of each composite
% number from 1 to n, in each row of x. Since the rows will have
% varying lengths, the rows are padded with ones at the end.
for i = 1:length(n)
x(i,:) = [unique(factor(n(i))) ones(1,p-length(unique(factor(n(i)))))];
end
output:
x =
1 1 1 1 1 1 1 1
2 1 1 1 1 1 1 1
2 3 1 1 1 1 1 1
2 1 1 1 1 1 1 1
3 1 1 1 1 1 1 1
2 5 1 1 1 1 1 1
For example, the last row contains the prime factors of 10, if we ignore the ones. I have made the matrix 8 columns wide to account for the many prime factors of numbers up to 10 million.
Thanks for any help!
This is not vectorization, but this version of the loop will save about half of the time:
for k = 1:numel(n)
tmp = unique(factor(n(k)));
x(k,1:numel(tmp)) = tmp;
end
Here is a quick benchmark for this:
function t = getPrimeTime
lower = 1;
upper = 2.^(1:8);
t = zeros(numel(upper),2);
for k = 1:numel(upper)
n = setdiff(lower:upper(k),primes(upper(k))); % contains composite numbers between lower to upper
t(k,1) = timeit(#() getPrime1(n));
t(k,2) = timeit(#() getPrime2(n));
disp(k)
end
p = plot(log2(upper),log10(t));
p(1).Marker = 'o';
p(2).Marker = '*';
xlabel('log_2(range of numbers)')
ylabel('log(time (sec))')
legend({'getPrime1','getPrime2'})
end
function x = getPrime1(n) % the originel function
p = 8;
x = ones(length(n),p); % Preallocated 2-D array of ones
for k = 1:length(n)
x(k,:) = [unique(factor(n(k))) ones(1,p-length(unique(factor(n(k)))))];
end
end
function x = getPrime2(n)
p = 8;
x = ones(numel(n),p); % Preallocated 2-D array of ones
for k = 1:numel(n)
tmp = unique(factor(n(k)));
x(k,1:numel(tmp)) = tmp;
end
end
Here's another approach:
p = 8;
lower = 1;
upper = 1e1;
p = 8;
q = primes(upper);
n = setdiff(lower:upper, q);
x = bsxfun(#times, q, ~bsxfun(#mod, n(:), q));
x(~x) = inf;
x = sort(x,2);
x(isinf(x)) = 1;
x = [x ones(size(x,1), p-size(x,2))];
This seems to be faster than the other two options (but is uses more memory). Borrowing EBH's benchmarking code:
function t = getPrimeTime
lower = 1;
upper = 2.^(1:12);
t = zeros(numel(upper),3);
for k = 1:numel(upper)
n = setdiff(lower:upper(k),primes(upper(k)));
t(k,1) = timeit(#() getPrime1(n));
t(k,2) = timeit(#() getPrime2(n));
t(k,3) = timeit(#() getPrime3(n));
disp(k)
end
p = plot(log2(upper),log10(t));
p(1).Marker = 'o';
p(2).Marker = '*';
p(3).Marker = '^';
xlabel('log_2(range of numbers)')
ylabel('log(time (sec))')
legend({'getPrime1','getPrime2','getPrime3'})
grid on
end
function x = getPrime1(n) % the originel function
p = 8;
x = ones(length(n),p); % Preallocated 2-D array of ones
for k = 1:length(n)
x(k,:) = [unique(factor(n(k))) ones(1,p-length(unique(factor(n(k)))))];
end
end
function x = getPrime2(n)
p = 8;
x = ones(numel(n),p); % Preallocated 2-D array of ones
for k = 1:numel(n)
tmp = unique(factor(n(k)));
x(k,1:numel(tmp)) = tmp;
end
end
function x = getPrime3(n) % Approach in this answer
p = 8;
q = primes(max(n));
x = bsxfun(#times, q, ~bsxfun(#mod, n(:), q));
x(~x) = inf;
x = sort(x,2);
x(isinf(x)) = 1;
x = [x ones(size(x,1), p-size(x,2))];
end

copy move forgery detection stuck with algorithm

I am trying to implement the paper detection of copy move forgery using histogram of oriented gradients.
The algorithm is:
Divide the image into overlapping blocks.
Calculate feature vectors for each block and store them in a matrix.
Sorting the matrix lexicographically
Using block matching to identify forged regions.
https://www.researchgate.net/publication/276518650_Detection_of_copy-move_image_forgery_using_histogram_of_orientated_gradients
I am stuck with the 3rd step and can't proceed.
The code I have implemented is:
clc;
clear all;
close all;
%read image
img = imread('006_F.png');
img=rgb2gray(img);
img=imresize(img, 1/4);
figure(1);
imshow(img);
b=16; %block size
nrc=5; %no. of rows to check
td=416; %threshold
[r, c]=size(img);%Rows and columns;
column=(r-b+1)*(c-b+1);
M= zeros(column,4);
Mi = zeros(1,2);
i=1;
disp('starting extraction of features');
for r1 = 1:r-b+1
for c1 = 1:c-b+1
% Extract each block
B = img(r1:r1+b-1,c1:c1+b-1);
features = extractHOGFeatures(B);%extracting features
M(i, :) = features;
Mi(i,:) = [r1 c1];
i=i+1;
end
end
[S, index] = sortrows(M , [ 1 2 3 4]);
P= zeros(1,6);
b2=r-b+1;
disp('Finding Duplicates');
for i = 1:column
iv = index(i);
xi=mod(iv,b2) + 1;
yi=ceil(iv/b2);
j = i+1;
while j < column && abs(i - j) < 5
jv=index(j);
xj=mod(jv,b2) + 1;
yj=ceil(jv/b2);
z=sqrt(power(xi-xj,2) + power(yi-yj,2));
% only process those whose size is above Nd
if z > 16
offset = [xi-xj yi-yj];
P = [P;[xi yi xj yj xi-xj yi-yj]];
end
j = j + 1;
end
end
rows = size(P,1);
P(:,6) = P(:,6) - min(P(:,6));
P(:,5) = P(:,5) - min(P(:,5));
maxValP = max(P(:,6)) + 1;
P(:,5) = maxValP .* P(:,5) + P(:,6);
mostfrequentval = mode(P(:,5));
disp('Creating Image');
idx = 2;
% Create a copy of the image and mask it
RI = img;
while idx < rows
x1 = P(idx,1);
y1 = P(idx,2);
x2 = P(idx,3);
y2 = P(idx,4);
if (P(idx,5) == mostfrequentval)
RI(y1:y1,x1:x1) = 0;
RI(y2:y2,x2:x2) = 0;
end
idx = idx + 1;
end;
After going through some references indicated in the paper you are working on (ref. [8] and [20]):
The lexicographic sorting is the equivalent of the alphabetical one, for numbers i.e., [1 1 1 1] < [1 1 2 1] < [2 3 4 5] < [2 4 4 5]
So, in your case, you case use the function sortrows() in the following way:
A = [1 1 1 1;1 1 1 2;1 1 1 4;1 2 2 2; 1 2 2 1; 1 4 6 3; 2 3 4 5; 2 3 6 6]; % sample matrix
[B,idx] = sortrows(A,[1 2 3 4]); % Explicit notation but it is the Matlab default setting so equivalent to sortrows(A)
It means: Sort the rows of A by first looking at the first column and, in case of equality, looking at the second one, and so on.
If your are looking for a reverse order, you specify '-' before the number of the column.
So in the end, your code is good and if the results are not as expected it has to come from another step of the implementation...
Edit: the parameter idx records the original index of the sorted rows.

How to do a ~= vector operation in matlab

I'm trying to write my own program to sort vectors in matlab. I know you can use the sort(A) on a vector, but I'm trying to code this on my own. My goal is to also sort it in the fewest amount of swaps which is kept track of by the ctr variable. I find and sort the min and max elements first, and then have a loop that looks at the ii minimum vector value and swaps it accordingly.
This is where I start to run into problems, I'm trying to remove all the ii minimum values from my starting vector but I'm not sure how to use the ~= on a vector. Is there a way do this this with a loop? Thanks!
clc;
a = [8 9 13 3 2 8 74 3 1] %random vector, will be function a once I get this to work
[one, len] = size(a);
[mx, posmx] = max(a);
ctr = 0; %counter set to zero to start
%setting min and max at first and last elements
if a(1,len) ~= mx
b = mx;
c = a(1,len);
a(1,len) = b;
a(1,posmx) = c;
ctr = ctr + 1;
end
[mn, posmn] = min(a);
if a(1,1) ~= mn
b = mn;
c = a(1,1);
a(1,1) = b;
a(1,posmn) = c;
ctr = ctr + 1;
end
ii = 2; %starting at 2 since first element already sorted
mini = [mn];
posmini = [];
while a(1,ii) < mx
[mini(ii), posmini(ii - 1)] = min(a(a~=mini))
if a(1,ii) ~= mini(ii)
b = mini(ii)
c = a(1,ii)
a(1,ii) = b
a(1,ii) = c
ctr = ctr + 1;
end
ii = ii + 1;
end