Assign values to multiple symbolic variables at the same time [duplicate] - matlab

This question already has answers here:
Define multiple variables at the same time in MATLAB
(2 answers)
Closed 7 years ago.
I wanna assign values to multiple symbolic variables at the same time.
For example,
syms a b c
% for several reasons, I have to define a, b, c as symbolic variables.
x = [a, b, c];
y = [1, 2, 3];
When I define matrix x and y like above,
I wanna get following answer.
a = 1
b = 2
c = 3
% Assign values to symbolic variables.
Of course, simply I can get this answer by using following code.
[a, b, c] = deal(1, 2, 3);
But I have to use matrix x and y instead of [a, b, c] and (1, 2, 3).
Because actually there are so many symbolic variables in matrix x when I calculate.
So I wanna use matrix.
In this case, if I use matrix x and y
x = deal(y);
The answer is just
x = 1 2 3
But I wanna get the answer,
a = 1
b = 2
c = 3
What should I do to assign values to variables by using matrix x and y?
Please answer my question.
Thank you.

I don't think you should be trying to do this, I am sure there must be some other choices you could make earlier to avoid this problem. But it can be done, probably more nicely than I have done.
syms a b c
x=[a b c]
y=[1 2 3]
%// We want to get the name of the variable from x, and the value from y
arrayfun(#(i) assignin('caller',char(x(i)),y(i)),1:length(x))

Related

Matrix generation from a vector

I have a column vector A. When A is a scalar I can use the colon operator to generate a vector like so
B = A-m:n:A+p
However, what I want to do is different. I want the result B to look like so,
[A-m, A-m+1 ... A ... , A+n-1, A+n]
I know I can accomplish this by using repmat on -m:n:p followed with a bsxfun added with the original A matrix.
Is there a more direct method?
If you just want to copy a handful instances of column vector v, you can always use
B = [v, v, v, ... v];
Or for row vector
B = [v ; v ; v ; ... v];
One easy vectorized way is this:
NewMatrix = diag(A)*ones(length(A),m+n+1) + ones(length(A),m+n+1)*diag(-m:1:n)
not a one-liner...
>> a=[1;2];
>> r=3:2:10;
>> repmat(a,1,size(r,2))+repmat(r,size(a,1),1)
ans =
4 6 8 10
5 7 9 11

Matlab integral over function of symbolic matrix

In an attempt to speed up for loops (or eliminate all together), I've been trying to pass matrices into functions. I have to use sine and cosine as well. However, when I attempt to find the integral of a matrix where the elements are composed of sines and cosines, it doesn't work and I can't seem to find a way to make it do so.
I have a matrix SI that is composed of sines and cosines with respect to a variable that I have defined using the Symbolic Math Toolbox. As such, it would actually be even better if I could just pass the SI matrix and receive a matrix of values that is the integral of the sine/cosine function at every location in this matrix. I would essentially get a square matrix back. I am not sure if I phrased that very well, but I have the following code below that I have started with.
I = [1 2; 3 4];
J = [5 6; 7 8];
syms o;
j = o*J;
SI = sin(I + j);
%SI(1,1) = sin(5*o + 1)
integral(#(o) o.*SI(1,1), 0,1);
Ideally, I would want to solve integral(#(o) o*SI,0,1) and get a matrix of values. What should I do here?
Given that A, B and C are all N x N matrices, for the moment, let's assume they're all 2 x 2 matrices to make the example I'm illustrating more succinct to understand. Let's also define o as a mathematical symbol based on your comments in your question above.
syms o;
A = [1 2; 3 4];
B = [5 6; 7 8];
C = [9 10; 11 12];
Let's also define your function f according to your comments:
f = o*sin(A + o*B + C)
We thus get:
f =
[ o*sin(5*o + 10), o*sin(6*o + 12)]
[ o*sin(7*o + 14), o*sin(8*o + 16)]
Remember, for each element in f, we take the corresponding elements in A, B and C and add them together. As such, for the first row and first column of each matrix, we have 1, 5 and 9. As such, A + o*B + C for the first row, first column equates to: 1 + 5*o + 9 = 5*o + 10.
Now if you want to integrate, just use the int command. This will find the exact integral, provided that the integral can be solvable in closed form. int also can handle matrices so it will integrate each element in the matrix. You can call it like so:
out = int(f,a,b);
This will integrate f for each element from the lower bound a to the upper bound b. As such, supposing our limits were from 0 to 1 as you said. Therefore:
out = int(f,0,1);
We thus get:
out =
[ sin(15)/25 - sin(10)/25 - cos(15)/5, sin(18)/36 - sin(12)/36 - cos(18)/6]
[ sin(21)/49 - sin(14)/49 - cos(21)/7, sin(24)/64 - sin(16)/64 - cos(24)/8]
Bear in mind that out is defined in the symbolic math toolbox. If you want the actual numerical values, you need to cast the answer to double. Therefore:
finalOut = double(out);
We thus get:
finalOut =
0.1997 -0.1160
0.0751 -0.0627
Obviously, this can generalize for any size M x N matrices, so long as they all share the same dimensions.
Caveat
sin, cos, tan and the other related functions have their units in radians. If you wish for the degrees equivalent, append a d at the end of the function (i.e. sind, cosd, tand, etc.)
I believe this is the answer you're after. Good luck!

Creating a matrix from a function handle (MATLAB)

What I intend to do is very simple but yet I haven't found a proper way to do it. I have a function handle which depends on two variables, for example:
f = #(i,j) i+j
(mine is quite more complicated, though)
What I'd like to do is to create a matrix M such that
M(i,j) = f(i,j)
Of course I could use a nested loop but I'm trying to avoid those. I've already managed to do this in Maple in a quite simple way:
f:=(i,j)->i+j;
M:=Matrix(N,f);
(Where N is the dimension of the matrix) But I need to use MATLAB for this. For now I'm sticking to the nested loops but I'd really appreciate your help!
Use bsxfun:
>> [ii jj] = ndgrid(1:4 ,1:5); %// change i and j limits as needed
>> M = bsxfun(f, ii, jj)
M =
2 3 4 5 6
3 4 5 6 7
4 5 6 7 8
5 6 7 8 9
If your function f satisfies the following condition:
C = fun(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. fun 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.
you can dispose of ndgrid. Just add a transpose (.') to the first (i) vector:
>> M = bsxfun(f, (1:4).', 1:5)
Function handles can accept matrices as inputs. Simply pass a square matrix of size N where the values corresponds to the row number for i, and a square matrix of size N where the values correspond to the column number for j.
N = 5;
f = #(i,j) i+j;
M = f(meshgrid(1:N+1), meshgrid(1:N+1)')

Mapping ids of two vectors

I have two vectors with the same elements but their order is not same. For eg
A
10
9
8
B
8
9
10
I want to find the mapping between the two
B2A
3
2
1
How can I do this in matlab efficiently?
I think the Matlab sort is efficient. So:
[~,I]=sort(A); %sort A; we want the indices, not the values
[~,J]=sort(B); %same with B
%I(1) and J(1) both point to the smallest value, and a similar statement is true
%for other pairs, even with repeated values.
%Now, find the index vector that sorts I
[~,K]=sort(I);
%if K(1) is k, then A(k) is the kth smallest entry in A, and the kth smallest
%entry in B is J(k)
%so B2A(1)=J(k)=J(K(1)), where BSA is the desired permutation vector
% A similar statement holds for the other entries
%so finally
B2A=J(K);
if the above were in script "findB2A" the following should be a check for it
N=1e4;
M=100;
A=floor(M*rand(1,N));
[~,I]=sort(rand(1,N));
B=A(I);
findB2A;
all(A==B(B2A))
There are a couple of ways of doing this. The most efficient in terms of lines of code is probably using ismember(). The return values are [Lia,Locb] = ismember(A,B), where Locb are the indices in B which correspond to the elements of A. You can do [~, B2A] = ismember(A, B) to get the result you want. If your version of MATLAB does not allow ~, supply a throwaway argument for the first output.
You must ensure that there is a 1-to-1 mapping to get meaningful results, otherwise the index will always point to the first matching element.
Here a solution :
arrayfun(#(x)find(x == B), A)
I tried with bigger arrays :
A = [ 7 5 2 9 1];
B = [ 1 9 7 5 2];
It gives the following result :
ans =
3 4 5 2 1
Edit
Because arrayfun is usually slower than the equivalent loop, here a solution with a loop:
T = length(A);
B2A = zeros(1, length(A));
for tt = 1:T
B2A(1, tt) = find(A(tt) == B);
end
I would go for Joe Serrano's answer using three chained sort's.
Another approach is to test all combinations for equality with bsxfun:
[~, B2A] = max(bsxfun(#eq, B(:), A(:).'));
This gives B2A such that B(B2A) equals A. If you want it the other way around (not clear from your example), simply reverse A and B within bsxfun.

Pulling values out of a vector in MATLAB [duplicate]

This question already has answers here:
Closed 12 years ago.
Possible Duplicates:
How do I do multiple assignment in MATLAB?
Is there anything like deal() for normal MATLAB arrays?
I want to put values of a vector in 2 variables, but it doesn't work.
vec = [2 3];
[m n] = vec;
I expected:
m = 2
n = 3
But I got an error.
It's a syntax problem or I can't do that?
There are many ways to assign values of a vector to different variables, but you cannot do it like that.
Easy way:
vec = [ 2 3 ];
m = vec(1);
n = vec(2);
Just another variation using an anonymous function.
vec = [2 3];
tuple = #(x) deal(x(1), x(2))
[m n] = tuple(vec)