MATLAB isequal function gives wrong answer for symbolic expression - matlab

In the following simple code:
syms x
isequal((x+1)^2, x^2+2*x+1)
MATLAB returns false, but two expressions are same!
What is wrong with the code?

These are not exactly the same expressions, and isequal() tests for expression equality. Try for example:
>> isequal(expand((x+1)^2), x^2+2*x+1)
ans =
logical
1
or,
>> isequal(simplify((x+1)^2), simplify(x^2+2*x+1))
ans =
logical
1
PS you could also use isAlways() to compare expressions,
isAlways((x+1)^2 == x^2+2*x+1)
ans =
logical
1

Related

Why does MATLAB fail to check the equality of this trigonometric expression

isequaln() is testing symbolic objects for equality as stated in the documentation. However, this is not the case with the following script.
syms a
f1=cos(a)^2;
f2=1-sin(a)^2;
isequaln(f1,f2)
ans =
logical
0
MATLAB does not return the correct answer. What does MATLAB do when comparing equality for symbolic expressions, compare strings (i.e. a typical scenario for regular expressions), or something else?
At the bottom of the documentation page, there is a section called "Tips", which contains the following item:
isequaln(A,B) checks if A and B are the same size and their contents are syntactically the same expression, treating NaN values as equal. To check whether the mathematical comparison A == B holds for all values of variables in A and B, use isAlways(A == B).
(emphasis mine)
isAlways does what you want:
syms a
f1 = cos(a)^2;
f2 = 1-sin(a)^2;
isAlways(f1 == f2)
This outputs true.
Alternatives:
>> simplify(f1-f2)
ans =
0
>> simplify(f1==f2)
ans =
symtrue

Matlabs "splitapply" used on functions with multiple parameters

I don't understand matlabs splitapply function:
>> f=#(t,x) sum(sum(t),sum(x))
f =
function_handle with value:
#(t,x)sum(sum(t),sum(x))
>> splitapply(f,[1,0;0,0],[1,1;2,2],1:2)
ans =
1 0
I expected the two matrices to be split into columns and the two first columns fed to f, resulting in a total sum of 4=(1+0)+(1+2). Then both the second columns should be fed to f, resulting in the number 3=(0+0)+(1+2).
So I expected
ans =
4 3
But quite obviously that is not what happend. And I am not sure why. If I use splitapply on functions with only one argument, it seems to do what I expect:
>> splitapply(#sum,[1,1;2,3],1:2)
ans =
3 4
I would be glad if someone could point out what is happening. This is the documentation if someone else can understand it better than me: https://de.mathworks.com/help/matlab/ref/splitapply.html
You probably want
f = #(t,x) sum([sum(t) sum(x)])
or
f = #(t,x) sum(t)+sum(x)
rather than
f = #(t,x) sum(sum(t), sum(x))
The latter is interpreted as compute the sum of sum(t) along the dimension given by sum(x).
With this correction,
>> f = #(t,x) sum([sum(t) sum(x)]);
>> splitapply(f,[1,0;0,0],[1,1;2,2],1:2)
ans =
4 3

How to assign values to variables in a handle function?

This is simplified but take as an example the following MATLAB function handle:
F = #(x)[x(1)-x(2);x(2)-x(3)]
The system has of course has many solutions. Is it possible to obtain a solution for a function like this one after substituting at least one variable? For example, substituting x(3)=1 the function would become:
G = #(x)[x(1)-x(2);x(2)-1]
And a solution for the other variables can be obtained. I use fsolve and it works quite well for the system of equations I have. Of course what I need to do can be done using the Symbolic Toolbox, but calling it in a big for loop makes it too slow to use for my code.
I'm trying to come up with some code that can return G given F and a set of indices in x to replace with given values.
What you're basically asking to do is have G call F with values in x reassigned based on a logical replacement index index and a set of replacement values values, which is doable but messy since anonymous functions can only have a single executable statement.
The solution is similar to what is done in this answer, but instead of using the functional form for subscripted reference we'll need to use the functional form for subscripted assignment: subsasgn. Here's what it would look like:
F = #(x)[x(1)-x(2); x(2)-x(3)];
values = [3 2 1];
index = logical([0 0 1]);
G = #(x) F(subsasgn(x, struct('type', '()', 'subs', {{index}}), values(index)));
And here's a test:
>> F([3 2 3])
ans =
1
-1
>> F([3 2 1]) % Replace the last element by 1
ans =
1
1
>> G([3 2 3]) % G handles replacing the last element by 1
ans =
1
1

Vectorization of multi-level indexing of structs in MATLAB

Say I have the following in MATLAB:
a(1).b.c = 4;
a(2).b.c = 5;
a(3).b.c = 7;
....
I would like to collect the values [4 5 7 ...] in a single array, without looping and in a vectorized manner.
I have tried:
>> a(:).b.c
# Error: Scalar index required for this type of multi-level indexing.
and
>> a.b.c
# Error: Dot name reference on non-scalar structure.
but they didn't work. The best I could come up with was:
arrayfun(#(x) x.b.c, a);
but as far as I understand arrayfun is not vectorized, or is it?
Your call to arrayfun seems idiomatic enough to me in Matlab. I don't think this is vectorized but it's well optimized and maybe the fastest way.
You should also try to benchmark with a loop to see if the JIT compiler performs well here. It's hard to know without testing.
You can do it in two lines:
>> s = [a.b];
>> y = [s.c]
y =
4 5 7
Another possible one-liner (less readable!):
>> y = squeeze(cell2mat( struct2cell([a.b]) ))
y =
4
5
7
a.b returns multiple outputs, so you can't expect to call a function on it. The best one-liner I can think of without using arrayfun is:
y = subsref([a.b], substruct('.', c));
Note that a.b.c is effectively the same as:
y = subsref(a.b, substruct('.', c))
Which is why it shouldn't work for non-scalar a.

How can I make XOR work for logical matrix in MATLAB?

>> XOR(X,X)
??? Undefined function or method 'XOR' for input arguments of type 'logical'.
Why XOR can't be used for logical matrix?
And I tried a more simple example:
>> A=[1 0;1 0];
>> B=[1 1;0 0];
>> XOR(A,B)
??? Undefined function or method 'XOR' for input arguments of type 'double'.
How can I properly use XOR?
It works for me.
A=[1 0;1 0];
B=[1 1;0 0];
xor(A,B)
ans =
0 1
1 0
Yet when I try this...
XOR(A,B)
??? Undefined function or method 'XOR' for input arguments of type 'double'.
See the difference. Leave caps off to fix the problem.
I think the ambiguity arises because of a MathWorks convention used in their documentation. When they show the name of a function in their help, they use all caps. For example, here is the help for xor.
>> help xor
XOR Logical EXCLUSIVE OR.
XOR(S,T) is the logical symmetric difference of elements S and T.
The result is logical 1 (TRUE) where either S or T, but not both, is
nonzero. The result is logical 0 (FALSE) where S and T are both zero
or nonzero. S and T must have the same dimensions (or one can be a
scalar).
Even so, when you use the function, you do so with lower case letters in the function name.
How about the following:
C = abs(A-B);
The statement above makes C the XOR of A and B, because xor is true where the entries are different from each other, and 1-0 or 0-1 will give 1 or -1 (and abs of that will give 1), while 0-0 and 1-1 are both 1.
If you really want, you can create an "XOR.m" file with the following definition:
function C=XOR(A,B)
% function C=XOR(A,B)
% INPUTS:
% A - m x n matrix, consisting only of 1s or 0s.
% B - m x n matrix, consisting only of 1s or 0s.
% OUTPUT:
% C - m x n matrix, containing the logical XOR of the elements of A and B
C=abs(A-B)
However, you should keep in mind that function calls in Matlab are horrifically slow, so you might want to just write out the definition that I gave you wherever you happen to need it.
Edit
I did not originally understand your question.... you need to use xor and not XOR, and if it is complaining that your matrices are doubles instead of logicals, then use A==1 and B==1 instead of A and B. Matlab is case sensitive when it comes to variable names and built-in functions such as the xor function.
See this post. C = A~=B