How to compare two matrices? - matlab

My goal is to compare two matrices: A and B in two different files:
function [Result]=test()
A_Mat= load('fileA', 'A')
B_Mat= load('fileB', 'B')
Result= A_Mat == B_Mat
end
The result that I want is a matrix that includes the difference between A and B.
The error that I have is:
error: binary operator '==' not implemented for 'scalar struct' by 'scalar struct' operations

The load function doesn't return what you think it returns. Reading the extensive and easily comprehensible MATLAB documentation always helps.
function Result=test()
load('fileA', 'A');
load('fileB', 'B');
Result = A == B
end

Use the isequal function.
isequal(A,B)

If you simply want the difference between A and B you should first use load as dasdingonesin suggested, and either check for full matrix equality with isequal or elementwise equality with ==. The difference, however, is simply given by - of course:
isequal(A,B); % returns a boolean for full matrix equality
A==B; % returns a logical matrix with element wise equality
A-B; % returns a matrix with differences between the two matrices
Do note that isequal can deal with matrices of unequal size (it will simply return 0), whilst both == and - will crash with the error Matrix dimensions must agree.

First, the operator == does work on matrices, and it returns a logical matrix of true/false (1/0) where the corresponding items are equal or different respectively. From the error you got it seems that you didn't read matrices from the file, but structs, and indeed, == doesn't work for structs.
You can use isequal for both structs and matrices. This function returns only one value - 1 or 0 (true/false).
ADDED
After seeing #dasdingonesin answer, who actually pointed to the exact problem, I just wanted to add that when you write
A_Mat= load('fileA', 'A')
it returns a struct as with the field A.
So:
A_Mat = s.A

Related

Boolean condition in vecorized operation Matlab

I have the following summation
where: s,k,q,l are integers {-n...,-2,-1,0,1,2,...,n}. 'P' and 'V' are stored as a (2n+1)*(2n+1) matrix, 'q' and 'f' are (2n+1)*1 array. How do I vecorize this operation? For loops separating the possible cases are ok for |n|<=10 but my objective is to do this in |n|>100 where it is taking too much time.
So far my idea is to find all corresponding indices for the valid combinations (s,k,q) and then operate all the products at once
preSum=q(valid_permutation).*f(valid_permutation).*P(valid_permutation).*V(valid_permutation);
and then sum all the elements to obtain the final result.
Well, I solved it by myself after a while.
This is my solution:
(initial variables)
n=50; kn=-n:n; Qq=kn;
Vql=rand(2*n+1); Pkl=rand(2*n+1); Fs=rand(2*n+1,1);
Now I create a couple of dummy variables:
pk=repmat(kn,(2*n+1),(2*n+1)^2);
pk=pk(:);
vk=repmat(kn,(2*n+1)^2,(2*n+1));
vk=vk(:);
fk=repmat(kn,(2*n+1)^3,1);
fk=fk(:);
Perms=[fk vk pk]; % Possible combinations of all 3 indices of the sum
Inds=find(sum(Perms,2)==0); % valid combinations that satisfy s+k+q==0
Now I do transform my matrix Vql, Pkl, Fs and Qq so they correspond to have the same layout as my dummy variables:
Vk_ord=flipud(Vql);
repmat(Vk_ord,(2*n+1),(2*n+1));
Vk_ord=Vk_ord(:);
Q_ord=repmat(Qq,(2*n+1)^2,2*n+1);
Q_ord=Q_ord(:);
Pk_ord=repmat(Pkl(:),(2*n+1)^2,1);
F_ord=repmat(Fs,(2*n+1)^3,1);
F_ord=Fkreord(:);
Finally, I concat all my rearranged vectors and take only the ones with a valid indices combination, compute the products and then the resulting summation:
preSum=[F_ord(Inds) Vk_ord(Inds) Q_ord(Inds) Pk_ord(Inds)];
preSum=prod(preSum,2);
Summation=sum(preSumation);

Matlab - Using two index arrays to operate on a sub-matrix

I'm trying to figure out how to access Matlab sub-arrays (part of an array) with a generic set of subscript vectors.
In general, the problem is defined as:
Given two n-dim endpoints of an array index (both size nd), one having the initial set of indices (startInd) and the other having the last set of indices (endInd), how to access the sub-matrix which is included between the pair of index-sets?
For example, I want to replace this:
Mat=rand(10,10,10,10);
Mat(2:7, 1:6, 1:6, 2:8) = 1.0;
With an operation that can accept any set of two n-dim vectors specifying the indices for the last operation, which is "abstractly" expressed as:
Mat=rand(10,10,10,10);
startInd=[2 1 1 2];
endInd =[7 6 6 8];
IndexVar=???
Mat(IndexVar) = 1.0;
Thus I want to access the sub-matrix Mat(2:7, 1:6, 1:6, 2:8) using a variable or some other generic form that allows a generic n-dim. Preferably not a loop (as it is slow).
I have tried using something of this nature:
% Generate each index list separately:
nDims=length(startInd);
ind=cell(nDims,1);
for j=1:nDims
ind{j}=startInd(j):1:endInd(j);
end
% Access the matrix:
S.type = '()';
S.subs = ind;
Mat=subsasgn(Mat,S,1.0)
This seems to get the job done, but is very slow and memory-expansive, but might give someone an idea...
If you don't mind looping over dimensions (which should be much faster than looping over array entries):
indexVar = arrayfun(#(a,b) colon(a,b), startInd, endInd, 'UniformOutput', false);
Mat(indexVar{:}) = 1;
This uses arrayfun (essentially a loop) to create a cell array with the indexing vectors, which is then expanded into a comma-separated list.
Now that I see your code: this uses the same approach, only that the loop is replaced by arrayfun and the comma-separated list allows a more natural indexing syntax instead of subsasgn.

bsxfun doesn't work as I expect on a constant function

In Matlab R2016a, I have a large set of small X-vectors and Y-vectors which are paired (e.g. 10,000 1x3 X-vectors paired with 10,000 1x3 Y vectors). For each {X,Y} pair, I want to calculate a 2-scalar-argument function for every pairwise combination of the elements in X and Y, (so in my example I would get 10,000 3x3 matrices).
I thought I could use bsxfun to perform these calculations, but it doesn't work when I try to do some simple tests. bsxfun(#(x,y) x*y,[1 2],[1 2]') returns:
ans =
1 2
2 4
Which is what I would expect. However, bsxfun(#(x,y) 1,[1 2],[1 2]') returns:
Error using bsxfun
Specified function handle produces invalid output dimensions. The function handle
must be a binary elementwise function.
Which makes no sense. The function handle is a binary elementwise function that always returns the scalar 1, so bsxfun should give the same result as ones(2,2), unless I'm not understanding how bsxfun works.
The inputs to the function handle that are passed to bsxfun are not scalars. In versions prior to R2016b, the inputs are either scalar or they are the same size.
FUNC can also be a handle to any binary element-wise function not listed
above. A binary element-wise function in the form of C = FUNC(A,B)
accepts arrays A and B of arbitrary but equal size and returns output
of the same size. Each element in the output array C is the result
of an operation on the corresponding elements of A and B only. FUNC must
also support scalar expansion, such that if A or B is a scalar, C is the
result of applying the scalar to every element in the other input array.
In releases since R2016b, they do not have to be equal sizes, but should be compatible sizes
In the example you have shown, the first input to the function handle is a scalar and the second is a vector (y) and the function is evaluated for every element of x and the output is expected to be the size of y
In the case you've posted, the call to bsxfun is essentially the equivalent of:
x = [1 2];
y = [1 2].';
yourfunc = #(x,y)x * y;
for k = 1:numel(x)
output(:,k) = yourfunc(x(k), y)
end
If you want to return a 1 for every entry, you need to replace your function with something that yields the appropriately sized output.
bsxfun(#(x,y)ones(max(size(x), size(y))), [1 2], [1 2]')
How you formulate the function handle really depends upon your specific problem

cellfun with conditionals in MATLAB

Is it possible to use cellfun with a conditional. For example, I have a 144x53 cell array, where the first four columns are of type string, the rest are floats. However, among the numbers, there are empty cells. I wonder if it is possible to use cellfun(#(x)sqrt(x), cellarray) with my array. As it is know, its not possible due to strings and empty cells. Otherwise, this is the solution that I use,
for n = 1:length(results)
for k = 1:length(results(1,:))
if ~isstr(results{n,k})
results{n, k} = sqrt(results{n,k});
end
end
end
Otherwise, is it possible to do a vectorization here?
You can create a logical array by checking if each element is numeric. And then use this to perform your cellfun operation on the subset of the cell array that contains numeric data.
C = {1, 2, 'string', 4};
% Logical array that is TRUE when the element is numeric
is_number = cellfun(#isnumeric, C);
% Perform this operation and replace only the numberic values
C(is_number) = cellfun(#sqrt, C(is_number), 'UniformOutput', 0);
% 1 1.4142 'string' 2
As pointed out by #excaza, you may also consider leaving it as a loop as it is more performant on newer versions of MATLAB (R2015b and newer).

Why are isscalar, isvector and ismatrix all true for A = 1?

Matlab has the following functions to check inputs:
isscalar to determine whether input is scalar
isvector to determine whether input is a vector
ismatrix to determine whether input is a matrix
For A = 1 (or any "scalar" input) all of the above return true.
Why do I see this counter-intuitive behavior?
And how would I indentify A = 1 as scalar?
I don't find it counter-intuitive at all. In Mathematics there exist vectors of 1 dimension (even though they are isomorphic with scalars). Also, a matrix can perfectly have size 1x1.
It is true that a single number could be considered a scalar, a 1-vector or a 1x1 matrix. Matlab's view is:
A scalar is considered to be a 1x1 matrix
An n-vector is just a 1 x n or n x 1 matrix
More generally: trailing singleton dimensions don't count. For example, a 3D-array of size 2x3x4 can also be considered, say, a 5D-array of size 2x3x4x1x1. This works without error:
>> a = rand(2,3,4);
>> a(2,2,2)
ans =
0.2575
>> a(2,2,2,1,1)
ans =
0.2575
Now, if you want to check if A is a vector, matrix, or multidimensional array with more than one element, use
numel(A)>1
The numel function returns the number of elements of its input argument.
Because Matlab interprets scalars as 1-by-1 arrays, see the size documentation.
Therefore, depending on your application, you would have to
use isscalar to distinguish a vector from a scalar (because it will return false for a vector)
use isvector to distinguish a matrix from a vector (because it will return false for a matrix)
Because if you are trying to figure out if a variable is a vector and not a scalar and you use isvector, both a scalar and a vector will return true - as pointed out in the question.