Using octave to map vector values - matlab

Can anyone explain how the following code:
Y(Y==0) = -1
sets all values of 0 to -1. For example for:
Y = [1 1 1 0 0 0 1]
we get:
Y = [1 1 1 -1 -1 -1 1]
What is confusing me is that Y==0 does not return a vector of indices.
An if I try to use the vector Y==0 directly I get the error:
Y([0 0 0 1 1 1 0]) = -1
error: subscript indices must be either positive integers or logicals
I would have naturally opted for:
Y(find(Y==0)) = -1
and would like to know why the above does not use find
TIA

This is called logical indexing. There is some documentation on gnu.org (see 4.6 Logical Values), but the best place to find info about it is probably in the MATLAB documentation.
Your example does not work because you are using an array of doubles, instead of a logical array, to index into Y. Consider the following (using Octave 3.6.2):
>> Y = [1 1 1 0 0 0 1]
Y =
1 1 1 0 0 0 1
>> idx = Y==0
idx =
0 0 0 1 1 1 0
>> idx_not_logical = [0 0 0 1 1 1 0]
idx_not_logical =
0 0 0 1 1 1 0
>> whos
Variables in the current scope:
Attr Name Size Bytes Class
==== ==== ==== ===== =====
Y 1x7 56 double
ans 1x7 7 logical
cmd_path 1x489 489 char
gs_path 1x16 16 char
idx 1x7 7 logical
idx_not_logical 1x7 56 double
Total is 533 elements using 631 bytes
>> Y(idx_not_logical)=-1
error: subscript indices must be either positive integers or logicals
>> Y(idx)=-1
Y =
1 1 1 -1 -1 -1 1

Y==0 returns a bool matrix as shown by:
> typeinfo(Y==0)
ans = bool matrix
That's why you can't index directly with [0 0 0 1 1 1 0], which is a matrix:
> typeinfo([0 0 0 1 1 1 0])
ans = matrix
If you wish to convert to boolean, use logical():
> typeinfo(logical([0 0 0 1 1 1 0]))
ans = bool matrix

Related

Acces 3D Matrix with 2D index and 1D vector

I have a 3D matrix A (size m*n*k) where m=latitude, n*longitude and k=time.
I want only specific values from first and second dimension, specified by a logical matrix B (size m*n), and I want only the timesteps specified by vector C (size k).
In the end this should become a 2D matrix D, since the first two dimesions will colapse to one.
What is the most easy approach to do this?
And also is it possible to combine logical with linear indizes here? For example B is logical and C is linear?
Sample code with rand:
A=rand(10,10,10);
B=randi([0 1], 10,10);
C=randi([0 1], 10,1);
D=A(B,C) %This would be my approach which doesnt work. The size of D should be sum(B)*sum(c)
Another example without rand:
A=reshape([1:27],3,3,3);
B=logical([1,0,0;1,0,0;0,0,0]);
C=(1,3); %get data from timestep 1 and 5
D=A(B,C);%What I want to do, but doesnÄt work that way
D=[1,19;2,20];%Result should look like this! First dimension is now all data from dimesion 1 and 2. New dimesion 2 is now the time.
A = rand(4,4,4);
B = randi([0 1], 4,4)
B =
1 1 0 1
1 0 1 1
0 0 1 0
1 0 1 1
>> C = randi([0 1],1,1,4);
>> C(:)
ans =
0
1
1
0
Then use bsxfun or implicit expansion expansion whith .* if newer Matlab version to generate a matrix of logical for you given coordinates.
>> idx = logical(bsxfun(#times,B,C))
idx(:,:,1) =
0 0 0 0
0 0 0 0
0 0 0 0
0 0 0 0
idx(:,:,2) =
1 1 0 1
1 0 1 1
0 0 1 0
1 0 1 1
idx(:,:,3) =
1 1 0 1
1 0 1 1
0 0 1 0
1 0 1 1
idx(:,:,4) =
0 0 0 0
0 0 0 0
0 0 0 0
0 0 0 0
Then your output is D = A(idx). However, note that this D is now an Nx1 array. Where N is number of true elements is B times number of true elements in C. 10x True in B and 2x True in C:
>> size(D)
ans =
20 1
An easy way to do it is to first reshape A into an m*n-by-k matrix, then do your indexing:
result = reshape(A, [], size(A, 3));
result = result(B, C);
In this case C can be either a logical vector or vector of indices.

How to make an array of matrix (of varying sizes)

I'm trying to get to grips with matlab, so this question is more about syntax than anything else.
I want to create a vector (1xn) of matrices. The matrices are all possibly of different dimensions eg. matrix 1 = 4 x 5, matrix 2 = 5 x 6 etc.
I tried using a for loop, but I had the following error:
Subscripted assignment dimension mismatch.
You can store an array of matrices of different sizes as a cell array of matrices. Often you'll want to create these cell arrays dynamically using the arrayfun function which will do this for you if you set the UniformOutput option to 0.
Example:
cols = [4 5 6];
rows = [1 2 3];
A = arrayfun(#(i) zeros(rows(i),cols(i)),1:3,'UniformOutput',0);
A{:}
Outputs:
ans =
0 0 0 0
ans =
0 0 0 0 0
0 0 0 0 0
ans =
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0

Matlab: How to insert zeros in specific places of vector

Can someone help me with the following problem in Matlab? I have a first vector containing the elements values. For example,
[2 8 4 9 3].
And a second one with the desired places in a second vector. For example,
[0 0 1 0 0 0 0 1 1 0 0 1 0 0 1].
Now I want to put the values from the first vector on the positions of the second one to end up with
[0 0 2 0 0 0 0 8 4 0 0 9 0 0 3].
What is the most efficient way of doing this when the size of the vector can be very large. (then thousands of elements)?
You can consider the y values as logical indicators, then use logical indexing to set those values to the values in x.
x = [2 8 4 9 3];
y = [0 0 1 0 0 0 0 1 1 0 0 1 0 0 1];
y(logical(y)) = x;
Alternatively, you could use
y(y==1) = x;
Use self-indexing:
% Your values:
V = [2 8 4 9 3];
% The desired locations of these values:
inds = [0 0 1 0 0 0 0 1 1 0 0 1 0 0 1];
% index the indices and assign
inds(inds>0) = V

Computing linear indices and counting non-zero entries of large sparse matrices in row-first order

Say I have a sparse non-rectangular matrix A:
>> A = round(rand(4,5))
A =
0 1 0 1 1
0 1 0 0 1
0 0 0 0 1
0 1 1 0 0
I would like to obtain the matrix B where the non-zero entries of A are replaced by their linear index in row-first order:
B =
0 2 0 4 5
0 7 0 0 10
0 0 0 0 15
0 17 18 0 0
and the matrix C that where the non-zero entries of A are replaced by the order in which they are found in a row-first search:
C =
0 1 0 2 3
0 4 0 0 5
0 0 0 0 6
0 7 8 0 0
I am looking for vectorized solutions for this problem that scale to large sparse matrices.
If I understand what you are asking, a couple of tranpositions should do the trick. The key is that find(A.') will do "row-first" indexing on A, where .' is the short hand for the transpose of a 2D matrix. So:
>> A = round(rand(4,5))
A =
0 1 0 1 1
0 1 0 0 1
0 0 0 0 1
0 1 1 0 0
then
B=A.';
B(find(B)) = find(B);
B=B.';
gives
B =
0 2 0 4 5
0 7 0 0 10
0 0 0 0 15
0 17 18 0 0
Here's a solution that doesn't require any transposing back and forth:
>> B = A; %# Initialize B
>> C = A; %# Initialize C
>> mask = logical(A); %# Create a logical mask using A
>> [r,c] = find(A); %# Find the row and column indices of non-zero values
>> index = c + (r - 1).*size(A,2); %# Compute the row-first linear index
>> [~,order] = sort(index); %# Compute the row-first order with
>> [~,order] = sort(order); %# two sorts
>> B(mask) = index %# Fill non-zero elements of B
B =
0 2 0 4 5
0 7 0 0 10
0 0 0 0 15
0 17 18 0 0
>> C(mask) = order %# Fill non-zero elements of C
C =
0 1 0 2 3
0 4 0 0 5
0 0 0 0 6
0 7 8 0 0
An outline (Matlab isn't on this machine, so verification is delayed):
You can use find() to get the coordinate list. Let T = A'; [r,c] = find(T)
From the coordinate list, you can create both B and C. Let valB = sub2ind([r,c],T) and valC = 1:length(r)
Use the sparse command to create B and C, e.g. B = sparse(r,c,valB), and then transpose, e.g. B = B' (or could do sparse(c,r,valB)).
Or, as #IanHincks suggests, let B = A'; B(find(B)) = find(B). (I'm not sure why .' is recommended, but, again, I don't have Matlab in front of to check.) For C, simply use C(find(C)) = 1:nnz(A). And transpose back, as he suggests.
Personally, I work with coordinate lists all the time, having migrated away from the sparse matrix representation, just to cut out the costs of index lookups.

Is there any function in MATLAB for changing the form of a matrix?

I have to get the unknown matrix by changing the form of a known matrix considering the following rules:
H = [-P'|I] %'
G = [I|P]
where
H is a known matrix
G is an unknown matrix which has to be calculated
I is the identity matrix
So for example, if we had a matrix,
H = [1 1 1 1 0 0;
0 0 1 1 0 1;
1 0 0 1 1 0]
its form has to be changed to
H = [1 1 1 1 0 0;
0 1 1 0 1 0;
1 1 0 0 0 1]
So
-P' = [1 1 1;
0 1 0;
1 1 0]
and in case of binary matrices -P = P.
Therefore
G = [1 0 0 1 1 1;
0 1 0 0 1 0;
0 0 1 1 1 0]
I know how to solve it on paper by performing basic row operations but haven't figured out how to solve it using MATLAB yet.
What is the method for solving the given problem?
If the order of columns in -P' doesn't matter, here's one solution using the function ISMEMBER:
>> H = [1 1 1 1 0 0; 0 0 1 1 0 1; 1 0 0 1 1 0]; %# From above
>> pColumns = ~ismember(H',eye(3),'rows') %'# Find indices of columns that
%# are not equal to rows
pColumns = %# of the identity matrix
1
0
1
1
0
0
>> P = -H(:,pColumns)' %'# Find P
P =
-1 0 -1
-1 -1 0
-1 -1 -1
>> G = logical([eye(3) P]) %# Create the binary matrix G
G =
1 0 0 1 0 1
0 1 0 1 1 0
0 0 1 1 1 1
NOTE: This solution will work properly for integer or binary values in H. If H has floating-point values, you will likely run into an issue with floating-point comparisons when using ISMEMBER (see here and here for more discussion of this issue).