Create symbolic matrix with function elements - matlab

I'm trying to create a nxm matrix with elements that are functions of other symbolic variables (in this case the time t) with the following code:
syms t x(t) L
N = [ 0, 0, ...
0, 0;
0, 0, ...
0, 0;
1 - 3*(x/L)^2 + 2*(x/L)^3, -x + 2*x^2/L - x^3/(L^2), ...
3*(x/L)^2 - 2*(x/L)^3, x^2/L - x^3/(L^2)];
The problem I have is that MATLAB converts the matrix N into a function, i.e. N(t). When I try to access a specific member
N(1, 1)
or submatrix
N(1, 3:4)
MATLAB trows the following error:
Symbolic function expected 1 inputs and received 2.
I understand the error message but it's not what I was expecting from the code. I dont want a symbolic matrix depending on t and I don't understand MATLABS behaviour in this case (for example why isn't N also a function of L or whatever). A solution is to create an zero symbolic matrix with
N = sym(zeros(3, 4));
and manually fill the elements
N(3, 1) = 1 - 3*(x/L)^2 + 2*(x/L)^3;
N(3, 2) = -x + 2*x^2/L - x^3/(L^2);
N(3, 3) = 3*(x/L)^2 - 2*(x/L)^3;
N(3, 4) = x^2/L - x^3/(L^2);
But as you can see this approach results in a lot of unecessary code. So, what is wrong with my first approach?

When you define x(t) it ends up as a symbolic function (symfun) instead of a symbolic object due to its dependency on t. This dependency is then carried over to your matrix N, making it a symbolic function dependent on t (which explains why it is only dependent on t and not L).
>> syms t x(t) L
>> N = ...
>> whos
Name Size Bytes Class Attributes
L 1x1 112 sym
t 1x1 112 sym
x 1x1 112 symfun
N 1x1 112 symfun
You can avoid the automatic conversion to symfun by the workarounds you do above, or you can define it explicitly when you create you matrix N, like this:
>> N = sym(char([ 0, 0, ...
0, 0;
0, 0, ...
0, 0;
1 - 3*(x/L)^2 + 2*(x/L)^3, -x + 2*x^2/L - x^3/(L^2), ...
3*(x/L)^2 - 2*(x/L)^3, x^2/L - x^3/(L^2)]));
The trick here is the combined use of the sym() and char() functions. If you only use sym() without turning the matrix into a string it won't work.
That being said, I personally find your second approach where you manually fill the elements to be more clear and easier to read.

Related

How can I factor specific variables out of a formula in Matlab?

Suppose I have a column vector of formulae like this
N =
4*k2 + 5*k3 + k1*x
7*k2 + 8*k3 + k1*y
and a column vector of symbolic variables like this
k =
k1
k2
k3
The formulae are linear with respect to k. I'd like to find a matrix M such that M*k equals N.
I can do this with N/k. However, that gives
[ (4*k2 + 5*k3 + k1*x)/k1, 0, 0]
[ (7*k2 + 8*k3 + k1*y)/k1, 0, 0]
which is correct, but not what I want. What I want is the matrix
x 4 5
y 7 8
which seems to me the simplest answer in that it involves no variables from k.
How do I convince Matlab to factor out the specified variables from a formula or a vector of formulae?
You can use coeffs, specifically the form
C = coeffs(p,vars) returns coefficients of the multivariate polynomial p with respect to the variables vars.
Since the first input needs to be a polynomial, you need to pass each component of N:
coeffs(N(1), k)
coeffs(N(2), k)
Or use a loop and store all results in a symbolic array:
result = sym('result', [numel(N) numel(k)]); % create symbolic array
for m = 1:numel(N)
result(m,:) = coeffs(N(m), k);
end
In your example, this gives
result =
[ 5, 4, x]
[ 8, 7, y]
Based on #LuisMendo's answer, I used coeffs. But there are a couple of problems with coeffs. The first is that its result doesn't include any coefficients that are 0. The second is that it doesn't seem to guarantee that the coefficients are ordered the same way as the variables in its second argument. I came up with the following function to replace coeffs.
Luckily coeffs returns a second result that lists the variables associated with each item in the first result. (It's more complicated if the formula is not linear.)
function m = factorFormula(f, v )
% Pre: f is a 1x1 sym representing a
% linear function of the variables in v.
% Pre: v is a column vector of variables
% Post: m is a row vector such that m*v equals f
% and the formulas in m do not contain the
% variables in v
[cx,tx] = coeffs(f,v)
n = size(v,1)
m = sym(zeros(1,n))
for i = 1:n
j = find(tx==v(i))
if size(j,2) == 1
m(i) = cx(j)
end
end
end
This only works for one formula, but it can be extended to a vector using the loop in #LuisMendo's answer or this equivalent expression in #Sanchises comment there.
cell2sym(arrayfun( #(f)factorFormula(f,k),N,'UniformOutput',false ) )
I hope there is a better answer than this.

Use fminsearch to find local minimizer and the minima at that value

I am having trouble using fminsearch: getting the error that there were not enough input arguments for my function.
f = #(x1,x2,x3) x1.^2 + 3.*x2.^2 + 4.*x3.^2 - 2.*x1.*x2 + 5.*x1 + 3.*x2 + 2.*x3;
[x, val] = fminsearch(f,0)
Is there something wrong with my function? I keep getting errors anytime I want to use it as an input function with any other command.
I am having trouble using fminsearch [...]
Stop right there and think some more about the function you're trying to minimize.
Numerical optimization (which is what fminsearch does) is unnecessary, here. Your function is a quadratic function of vector x; in other words, its value at x can be expressed as
x^T A x + b^T x
where matrix A and vector b are defined as follows (using MATLAB notation):
A = [ 1 -1 0;
-1 3 0;
0 0 4]
and
b = [5 3 2].'
Because A is positive definite, your function has one and only one minimum, which can be computed in MATLAB with
x_sol = -0.5 * A \ b;
Now, if you're curious about the cause of the error you ran into, have a look at fuesika's answer; but do without fminsearch whenever you can.
It is exactly what Matlab is telling you: your function expects three arguments. You are passing only one.
Instead of
[x, val] = fminsearch(f,0)
you should call it like
[x, val] = fminsearch(f,[0,0,0])
since you define the function f to accept a three dimensional vector as input only.
You can read more about the specification of fminsearch in the online documentation at http://mathworks.com/help/matlab/ref/fminsearch.html:
x = fminsearch(fun,x0) starts at the point x0 and returns a value x
that is a local minimizer of the function described in fun. x0 can be
a scalar, vector, or matrix. fun is a function_handle.

Why does my function return two values when I only return one?

So I'm trying to implement the Simpson method in Matlab, this is my code:
function q = simpson(x,f)
n = size(x);
%subtracting the last value of the x vector with the first one
ba = x(n) - x(1);
%adding all the values of the f vector which are in even places starting from f(2)
a = 2*f(2:2:end-1);
%adding all the values of the f vector which are in odd places starting from 1
b = 4*f(1:2:end-1);
%the result is the Simpson approximation of the values given
q = ((ba)/3*n)*(f(1) + f(n) + a + b);
This is the error I'm getting:
Error using ==> mtimes
Inner matrix dimensions must agree.
For some reason even if I set q to be
q = f(n)
As a result I get:
q =
0 1
Instead of
q =
0
When I set q to be
q = f(1)
I get:
q =
0
q =
0
I can't explain this behavior, that's probably why I get the error mentioned above. So why does q have two values instead of one?
edit: x = linspace(0,pi/2,12);
f = sin(x);
size(x) returns the size of the array. This will be a vector with all the dimensions of the matrix. There must be at least two dimensions.
In your case n=size(x) will give n=[N, 1], not just the length of the array as you desire. This will mean than ba will have 2 elements.
You can fix this be using length(x) which returns the longest dimension rather than size (or numel(x) or size(x, 1) or 2 depending on how x is defined which returns only the numbered dimension).
Also you want to sum over in a and b whereas now you just create an vector with these elements in. try changing it to a=2*sum(f(...)) and similar for b.
The error occurs because you are doing matrix multiplication of two vectors with different dimensions which isn't allowed. If you change the code all the values should be scalars so it should work.
To get the correct answer (3*n) should also be in brackets as matlab doesn't prefer between / and * (http://uk.mathworks.com/help/matlab/matlab_prog/operator-precedence.html). Your version does (ba/3)*n which is wrong.

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!

How to apply a probability to a cell in MATLAB?

Just a simple question today. If I have an m*n matrix and I want to cycle through every value in it and apply a probability based function.
Basically, if the probability is p, then each value in the matrix has p chance of having the function applied to it.
I have the loop and the function itself all worked out, but I haven't found how to actually apply the probability itself.
Any advice would be greatly appreciated! Thanks in advance.
Here's your data matrix:
>> X = reshape(1:9, 3, 3);
and you want to (possibly) apply the following function to every element (note how I've vectorized it, so that it can take a matrix as an argument)
>> f = #(x) x.^2;
You want to apply the function with probability p
>> p = 0.25;
So generate some random numbers between 0 and 1, and see which ones are less than p
>> idx = rand(3,3) < p;
And now apply the function to the relevant indexes
>> X(idx) = f(X(idx));
Here's your result:
>> X
X =
1 16 7
2 5 64
3 6 81
The trick is that you can generate the random numbers first, and then apply the other formulas.
For example:
R = rand(m,n) < p
Now each value of R(row,col) corresponds to the outcome that you need to process your original matrix(row,col).
So I suggest applying your function to every cell and then setting the values to a default value based on some probability. So lets assume M is the result of applying to function to everycell:
default = NaN % Or 0 or whatever
p = 0.8;
M(rand(size(M)) > p) = default;
I think you might have to reshape m after this... not sure
M = reshape(M, m, n);