matlab/octave compare vectors using dictionary order? - matlab

Is there a succinct way in Octave to compare two vectors using dictionary order (lexicographic) order?
i.e. I'd like to compare two vectors a , b by the first element, return result if they differ; otherwise compare the second element, and so on..
For example, if a = [0 1 5] , b = [0 2 1], I'd like to have
a <? b
for some operator/function <? to return true.
If I simply do a < b, this will return a vector of logical values.
ans =
0 1 0

The following will work for both MATLAB and Octave...
You can create a comparison function using find like so:
lexlt = #(a, b) find([a < b true], 1) < find([a > b true], 1);
It will return true if the first vector argument is lexographically less than the second, and false otherwise (if it's greater than or equal to it). For example:
>> a = [0 1 5];
>> b = [0 2 1];
>> lexlt(a, a)
ans =
logical
0
>> lexlt(a, b)
ans =
logical
1
>> lexlt(b, a)
ans =
logical
0
And here's the corresponding function for a "greater than" comparison (i.e. the first argument is lexographically greater than the second):
lexgt = #(a, b) find([a > b true], 1) < find([a < b true], 1);

In Octave you can use issorted:
result = ~isequal(a,b) && issorted([a;b],'rows');
In MATLAB you can use issortedrows:
result = issortedrows([a;b],'strictascend')

Find first index which they are not equal. Then, compare them in the specified index.
idx = find(a ~= b);
result = a(idx(1)) < b(idx(1)); % if length(idx) > 0

Related

Matrix logical matlab

I am trying to get M. To do this, it is necessary for Matlab to relate column 1 of A to column 1 of 𝐡^𝑇and build a matrix M with 1 and 0 depending on whether in position 𝐴[𝑖,𝑗] and 𝐡^𝑇[𝑖,𝑗] are equal to 1
A = [1 0 1; 0 1 1; 0 0 1 ];
B = [0 0 1 ; 0 1 0; 1 1 1];
for i = 1:3
for j =1:3
if A(i,j) == BT(i,j) && A(i,j)==1;
Z(i,j) = 1
end
end
end
When you use "if A(i,j) == BT(i,j) && A(i,j)==;" you are comparing individual elements. Instead you want to be comparing columns:
A(:, i) and BT(:, j).
Precisely, you want
for i = 1:3
for j = 1:3
M(i,j) = any( A(:,i) & BT(:,j) );
end
end
OR
You are comparing the columns of BT and the columns of A.
That is to say, the rows of B and the columns of A. You want to see if there are any occasions when both of the elements are 1. Thus you can compare the products of the terms in the rows of B and columns of A.
i.e. M = logical(B * A) should also give you the desired output.
NOTE that the data in B are different in your image examples and in your code.

Matlab- sparse- element wise division

Consider the following;
A = [1 0 0; 0 2 0; 0 0 5];
B = [2 0 0; 0 4 0; 0 0 10];
A = sparse(A);
B = sparse(B);
C = B./A
I expected matlab to do sparse operations only on non-zero entries. But it also does operation on zero entries and returnNAN.
I saw few solutions in this site.
1. Using logical indexing
>> c = B(logical(A))./A(logical(A))
c =
(1,1) 2
(2,1) 2
(3,1) 2
As you can see, this does not preserve the sparse structure.
2. Replacing output with zero, where A is zero
This is an elegant solution if B./A is the only operation I do. What if I B./A is a part of a bigger operation? E.g K = 3*(B./A)*rand(3) + 5*(A./B)*rand(3)
Is there a simple way of dividing sparse matrices(having same structure) element-wise without getting NAN?
When you index (logical or not), you need to index the result as well to preserve the sparse structure.
idx = find(A); %# assumes A and B have the same sparsity pattern!
C = A; %# initialize C to have the correct size and shape
C(idx) = B(idx)./A(idx);
One more option:
B = spfun(#(x) 1./x, B);
C = A.*B;

Comparison between vectors in matlab

if i have A=[3 4 5 6] and B=[6 5 4] then i want to compare each value in A with all values in B,
if this value is greater then increase counter with 1 and if this value is equal then increase another counter with 1
If you want an array that corresponds to the result of each value in A, you could do
arrayfun(#(x) sum(x > B), A)
this gives [0, 0, 1, 2]. If you want the total sum you would just put sum(...) around that:
sum(arrayfun(#(x) sum(x > B), A))
this gives 3.
For the equal-counter, you can simply change > to ==:
arrayfun(#(x) sum(x == B), A)
this gives [0, 1, 1, 1].
Another approach in comparison to arrayfun would be bsxfun. Though it takes a bit more memory, I'd argue that it's faster. arrayfun is implicitly a for loop and using loops in MATLAB is usually slower than vectorized approaches.
If you want the greater than case, use the gt function with bsxfun, so:
>> A = [3 4 5 6];
>> B = [6 5 4];
>> sum(bsxfun(#gt, A, B.'), 1)
ans =
0 0 1 2
If you want to accumulate all of the values that match the criterion, you can put another sum call within this bsxfun call:
>> sum(sum(bsxfun(#gt, A, B.'), 1))
ans =
3
For the greater than or equal case, use ge:
>> sum(bsxfun(#ge, A, B.'), 1)
ans =
0 1 2 3
For the equality case, use eq:
>> sum(bsxfun(#eq, A, B.'), 1)
ans =
0 1 1 1
Again, if you want to accumulate all of the values that match the criterion, nest another sum call with the above results.

Can't figure out "if else" code correctly?

if APC<-2.9079
BUYz='z'
SELLy='y'
elseif APC>0.44
BUYy='y'
SELLz='z'
else
end
x and y are both single column matrices.
I want the system to check if the APC column is above or below the values as mentioned above, if yes, pick up corresponding values from x and y.
Do you think I have entered this correctly?
When I try the code it does not create BUYy or any of the others.
Thanks for all the help.
Clarification:
I have loaded an excel file in Matlab using xlsread. It has columns such as x, y, APC, Date etc.
I am using the "if else" statement in the command window after loading the file.
First a brief introduction to if and elseif for vectors.
Suppose A = [1 2 3], then the following will not result in B = 5.
if A > 2
B = 5;
end
The reason for this is because what the if sees is (A > 2) == [0 0 1]. The first 0 will cause the statement to be false, thus it will skip the rest.
Similarly, the following will also not result in B = 5.
if A < 2
B = 5;
end
The reason for this is because the if now sees (A < 2) == [1 0 0]. The if requires all of the elements to be true for it to "jump into it". The two below are equivalent:
if A < x
and
if all(A < x)
elseif behaves the exact same way.
Suppose y = [1 2 3], doing x = 'y' will not give you x = [1 2 3] but x = y (the character "y", not the variable. If you want the x variable to be equal to the y variable you simply do x = y.
So, what can you do?
If I understand you correctly, you have a vectors similar to this (might be decimals, but that doesn't matter).
APC = [1, -3, 4, -2, 0];
x = [1 2 3 4 5];
y = [6 7 8 9 10];
You want BUYx = x(2), and SELLy = y(2) since the second element is the only one in APC that's less than -2.9079.
You also want BUYy = [y(1), y(3)] and SELLx = [x(1), x(3)], since the first and third element of APC is larger than 0.44.
What you can do is:
BUYx = x(APC < -2.9079)
SELLy = y(APC < -2.9079)
BUYy = y(APC > 0.44)
SELLx = x(APC > 0.44)
This returns:
BUYx =
2
SELLy =
7
BUYy =
6 8
SELLx =
1 3
If you only want the first elements and not all of them, you can use find like this:
BUYx = x(find(APC < -2.9079,1,'first'))
SELLy = y(find(APC < -2.9079,1,'first'))
BUYy = y(find(APC > 0.44,1,'first'))
SELLx = x(find(APC > 0.44,1,'first'))
find(x < y, 5, 'first') find the first 5 elements where x < y. find(APC < -2.9079, 1, 'first') finds only the first element where APC < -2.9079.
or just do as the first approach and then: BUYx = BUYx(1) to only get the first elements.
It might be I have misinterpreted your question, but I think this will get you well on your way nevertheless. Good luck!

How to "chop up" matrix in Matlab using combination of logical indexing and slicing?

I have a matrix M that looks similar to this:
M = [ 1, 2, 3, 0, 0;
1, 2, 0, 0, 0;
2, 3, 4, 5, 0;
4, 5, 6, 0, 0;
1, 2, 3, 4, 5;
]
I'm trying to get a column vector with the rightmost non-zero value of each row in A, but ONLY for the rows that have the first column == 1.
I'm able to calculate a filter for the rows:
r = M( :, 1 ) == 1;
> r = [ 1; 1; 0; 0; 1 ]
And I have a set of indices for "the rightmost non-zero value of each row in M":
> c = [ 3, 2, 4, 3, 5 ]
How do I combine these in a slicing of A in order to get what I'm looking for? I'm looking for something like:
A( r, c )
> ans = [ 3; 2; 5 ]
But doing this gets me a 3x3 matrix, for some reason.
The shortest way I can think of is as follows:
% Get the values of the last non-zero entry per row
v = M(sub2ind(size(M), 1:size(M,1), c))
% Filter out the rows that does not begin with 1.
v(r == 1)
This seems to work (I assume other operations defining r,c have been performed):
M(sub2ind(size(A),find(r==1).',c(r==1))).'
Short interpretation of the problem and solution:
M( r, c )
gives a 3 x 5 matrix (not 3 x 1 as desired) due to mixing of logical and subscript indices. The logical indices in r pick out rows in A with r==1. Meanwhile row array c picks out elements from each row according to the numeric index:
ans =
3 2 0 3 0
0 2 0 0 0
3 2 4 3 5
What you really want are indices into the rightmost nonzero elements in each row starting with 1. The solution uses linear indices (numeric) to get the correct elements from the matrix.
I think this should do the trick. I wonder if there is more elegant way of doing this though.
% get only rows u want, i.e. with first row == 1
M2 = M(r,:);
% get indices of
% "the rightmost non-zero value of each row in M"
% for the rows u want
indicesOfinterest = c(r==1);
noOfIndeciesOfinterest = numel(indicesOfinterest);
% desired output column vector
output = zeros(noOfIndeciesOfinterest, 1);
% iterate through the indeces and select element in M2
% from each row and column indicated by the indice.
for idx = 1:noOfIndeciesOfinterest
output(idx) = M2(idx, indicesOfinterest(idx));
end
output % it is [3; 2 ; 5]
You can use
arrayfun(#(x) M(x,c(x)), find(r))
But unless you need r and c for other purposes, you can use
arrayfun(#(x) M(x,find(M(x,:),1,'last')), find(M(:,1)==1))
Here is a way to do it using linear indexing:
N = M';
lin_index = (0:size(N,1):prod(size(N))-1) + c;
v = N(lin_index);
v(r)