Matrix of symbolic functions - matlab

I would like to define a matrix of symbolic functions (not variables) in Matlab. In the workspace I would like it to be an element of class symfun of size N-by-M (where N and M are positive integers).

You can't create a matrix of symfun class elements (possibly for the same reason that one can't create a matrix of function handles), but you can create a symbolic function that returns a matrix of symbolic expressions:
syms x y z;
Afun = symfun([x+y y-z;y/x z-1],[x y z])
B = Afun(sym(pi),cos(y),z^2)
Of course you won't be able to directly access the elements of Afun until you evaluate it, though you can use formula to extract them:
Amat = formula(Afun);
Amat(1)
It is possible to concatenate symfuns into a matrix, provided that they all have the same input arguments (the arguments don't need to be used). However, the concatenation still does not form a matrix of symfuns – it just concatenates the formulas themselves so you still end up with one symfun as above.
Another option is to create a matrix of symbolic expressions, e.g.:
syms x y z;
A = [2*x 3*y^2 x+z;
-y^3+1 sin(x) sym('pi');
3.5 exp(-z) 1/x];
which can be evaluated using subs:
B = subs(A,{x,y,z},{sym(pi),cos(y),z^2})
And normal matrix operations work, e.g.:
B = subs(A(2,:),{x,y,z},{sym(pi),cos(y),z^2})

I don't know how to create a matrix, but a cell is possible:
c={symfun(x+y, [x y]),symfun(x+2*y, [x y]);symfun(x+3*y, [x y]),symfun(x+4*y, [x y])}
Maybe this is sufficient in your case.

If you for example want to arrange some anonymous symbolic functions in a vector you can do as following:
z = sym([]); %declare z as an empty symbolic array
N = 6; %array size
for i = 1:N
syms(sprintf('z%d(t)', i)) %declare each element in the array as a single symbolic function
zz = symfun(sym(sprintf('z%d(t)', i)), t); %declare each element to a symbolic "handle"
z = [z;zz]; %paste the symbolic "handle" into an array
end
Be aware that matlab treats z as an 1x1 symbolic function even though it contains more elements.
z will still behave like a vector, so you can use it as a normal vector in matrix-vector operations.

Related

Symbolic differentiation

Well, I know, for a normal case, if I define
syms x,y
K = f(x,y)
as an explicit expression on x and y, we can do diff(K, x) or diff(K, y) to obtain what we want.
But right now, if I have another function
J = g(K)
And I want to do
diff(J, K)
then error occurs as:
'The second argument must be a variable or a non negative integer specifying the number of differentiations.'
So, in a nutshell, how to solve this kind of 'chained expression differentiation'? (Sorry for this ambiguous description.)
According to the diff function in Matlab,
The first argument should be the function you want to differentiate
and the remaining arguments must be either the symbolic variables or a
non-negative number which represents the number of differentiation.
So, the error.
The second argument must be a variable or a non negative integer specifying the number of differentiations.
In the code diff(J, K) is saying that K is a symbolic variable to the Matlab but in actual case, K is an expression in the terms of x and y. So, this is the reason why Matlab is throwing that error.
So if you want to differentiate a chained function with variables x, y then you need to mention each symbolic variables explicitly within the diff() function whenever you want to differentiate that expression. The code to do so is below.
% define the symbolic functions
% as f(x,y) and g(K)
syms f(x,y) g(K)
% create the functions
K = f(x,y)
J = g(K)
% differentiate the functions with
% respect to x and y respectively.
% ------------------------
% differentiate w.r.t x
diff_K_x = diff(K, x)
% differentiate w.r.t y
diff_K_y = diff(K, y)
% -----------------------
% differentiate the function J with respect to x and y both
diff_K_xy = diff(J,x,y)

Create a symbolic function of different length vectors in MATLAB Symbolic Toolbox

My overall goal is to use the MATLAB symbolic toolbox to simplify the process of formulating and solving for the sensitivities of solutions to ordinary differential equations with respect to the parameters in the equations. In my case I have an ODE with 2 states and 10 parameters. A smaller, but representative, example would look like
X = sym('X', [2 1]) % Vector representing state variables
p = sym('p', [3 1]) % Vector representing parameters
% Fitzhugh Nagumo Equations
rhs_1 = symfun(p(3)*(X(1) - X(1)^3/3 + X(2)), [X; p])
rhs_2 = symfun(-(X(1) - p(1) + p(2)*X(2))/p(3), [X; p])
I can then get the partial derivatives, which are used to solve for the sensitivities, of the RHS of the ODE wrt to the parameters using a command like 'gradient(rhs_1, p)'. But then I would like to convert this gradient to a matlab function that is a function of the vectors X and p, not a function of the elements of these vectors. I need these functions to be of this form because otherwise I cannot use the CVODES solver in the sundialsTB toolbox. Is this possible? Is there an easier way to accomplish what I am trying to do?
Recognizing that a comma-separated list of function inputs is really just a cell array, you can do this by converting your vector inputs to a cell arrays of scalar using mat2cell:
x=1:2;
p=1:3;
v = mat2cell([x(:);p(:)],ones(numel(x)+numel(p),1),1);
y1 = rhs_1(v{:})
y2 = rhs_2(v{:})

Numerically integrate a function f(x) over x using MATLAB where f(x) has another argument y which is a vector

I would like to numerically integrate a vector which represents a function f(x) over the range of x specified by bounds x0 and x1 in Matlab. I would like to check that the output of the integration is correct and that it converges.
There are the quad and quadl functions that serve well in identifying the required error tolerance, but they need the input argument to be a function and not the resulting vector of the function. There is also the trapz function where we can enter the two vectors x and f(x), but then it computes the integral of f(x) with respect to x depending on the spacing used by vector x. However, there is no given way using trapz to adjust the tolerance as in quad and quadl and make sure the answer is converging.
The main problem why I can't use quad and quadl functions is that f(x) is the following equation:
f(x) = sum(exp(-1/2 *(x-y))), the summation is over y, where y is a vector of length n and x is an element that is given each time to the function f(x). Therefore, all elements in vector y are subtracted from element x and then the summation over y is calculated to give us the value f(x). This is done for m values of x, where m is not equal to n.
When I use quadl as explained in the Matlab manual, where f(x) is defined in a separate function .m file and then in the main calling file, I use Q = quadl(#f,x0,x1,tolerance,X,Y); here X is a vector of length m and Y is a vector of length L. Matlab gives an error: "??? Error using ==> minus
Matrix dimensions must agree." at the line where I define the function f(x) in the .m function file. f(x) = sum(exp(-1/2 *(x-y)))
I assume the problem is that Matlab treats x and y as vectors that should be of the same length when they are subtracted from each other, whereas what's needed is to subtract the vector Y each time from a single element from the vector X.
Would you please recommend a way to solve this problem and successfully numerically integrate f(x) versus x with a method to control the tolerance?
From the documentationon quad it says:
The function y = fun(x) should accept a vector argument x and return a vector result y, the integrand evaluated at each element of x.
So every time we call the function, we need to evaluate the integrand at each given x.
Also, to parameterize the function call with the constant vector Y, I recommend an anonymous function call. There's a reasonable demo here. Here's how I implemented your problem in Matlab:
function Q = test_num_int(x0,x1,Y)
Q = quad(#(x) myFun(x,Y),x0,x1);
end
function fx = myFun(x,Y)
fy = zeros(size(Y));
fx = zeros(size(x));
for jj=1:length(fx)
for ii=1:length(Y)
fy(ii) = exp(-1/2 *(x(jj)-Y(ii)));
end
fx(jj) = sum(fy);
end
end
Then I called the function and got the following output:
Y = 0:0.1:1;
x0 = 0;
x1 = 1;
Q = test_num_int(x0,x1,Y)
Q =
11.2544
The inputs for the lower and upper bound and the constant array are obviously just dummy values, but the integral converges very quickly, almost immediately. Hope this helps!
I believe the following would also work:
y = randn(10,1);
func = #(x) sum(exp(-1/2 *(x-y)));
integral(func,0,1,'ArrayValued',true)

Matlab: determinant of a matrix of vectors

I have a 2x2 matrix, each element of which is a 1x5 vector. something like this:
x = 1:5;
A = [ x x.^2; x.^2 x];
Now I want to find the determinant, but this happens
B = det(A);
Error using det
Matrix must be square.
Now I can see why this happens, MATLAB sees A as a 2x10 matrix of doubles. I want to be able to treat x as an element, not a vector. What I'd like is det(A) = x^2 - x^4, then get B = det(A) as a 1x5 vector.
How do I achieve this?
While Matlab has symbolic facilities, they aren't great. Instead, you really want to vectorize your operation. This can be done in a loop, or you can use ARRAYFUN for the job. It sounds like ARRAYFUN would probably be easier for your problem.
The ARRAYFUN approach:
x = 1:5;
detFunc = #(x) det([ x x^2 ; x^2 x ]);
xDet = arrayfun(detFunc, x)
Which produces:
>> xDet = arrayfun(detFunc, x)
xDet =
0 -12 -72 -240 -600
For a more complex determinant, like your 4x4 case, I would create a separate M-file for the actual function (instead of an anonymous function as I did above), and pass it to ARRAYFUN using a function handle:
xDet = arrayfun(#mFileFunc, x);
Well mathematically a Determinant is only defined for a square matrix. So unless you can provide a square matrix you're not going to be able to use the determinant.
Note I know wikipedia isn't the end all resource. I'm simply providing it as I can't readily provide a print out from my college calculus book.
Update: Possible solution?
x = zeros(2,2,5);
x(1,1,:) = 1:5;
x(1,2,:) = 5:-1:1;
x(2,1,:) = 5:-1:1;
x(2,2,:) = 1:5;
for(n=1:5)
B(n) = det(x(:,:,n));
end
Would something like that work, or are you looking to account for each vector at the same time? This method treats each 'layer' as it's own, but I have a sneaky suspiscion that you're wanting to get a single value as a result.

Vector to Matrix syntax in MATLAB

Is there a way to combine 2 vectors in MATLAB such that:
mat = zeros(length(C),length(S));
for j=1:length(C)
mat(j,:)=C(j)*S;
end
Using normal MATLAB syntax similar to:
mat = C * S(1:length(S))
This gives a "Inner matrix dimensions must agree error" because it's trying to do normal matrix operations. This is not a standard Linear Algebra operation so I'm not sure how to correctly express it in MATLAB, but it seems like it should be possible without requiring a loop, which is excessively slow in MATLAB.
From your description, it sounds like a simple matrix operation. You just have to make sure you have the right dimensions for C and S. C should be a column vector (length(C)-by-1) and S should be a row vector (1-by-length(S)). Assuming they are the right dimensions, just do the following:
mat = C*S;
If you're not sure of their dimensions, this should work:
mat = (C(:))*(S(:)');
EDIT: Actually, I went a little crazy with the parentheses. Some of them are unnecessary, since there are no order-of-operation concerns. Here's a cleaner version:
mat = C(:)*S(:)';
EXPLANATION:
The matrix multiplication operator in MATLAB will produce either an inner product (resulting in a scalar value) or an outer product (resulting in a matrix) depending on the dimensions of the vectors it is applied to.
The last equation above produces an outer product because of the use of the colon operator to reshape the dimensions of the vector arguments. The syntax C(:) reshapes the contents of C into a single column vector. The syntax S(:)' reshapes the contents of S into a column vector, then transposes it into a row vector. When multiplied, this results in a matrix of size (length(C)-by-length(S)).
Note: This use of the colon operator is applicable to vectors and matrices of any dimension, allowing you to reshape their contents into a single column vector (which makes some operations easier, as shown by this other SO question).
Try executing this in MATLAB:
mat = C*S'
As In:
C = [1; 2; 3];
S = [2; 2; 9; 1];
mat = zeros(length(C),length(S));
for j=1:length(C)
mat(j,:)=C(j)*S;
end
% Equivalent code:
mat2 = C*S';
myDiff = mat - mat2
Do you mean the following?
mat = zeros(length(C),length(S));
for j=1:length(C)
mat(j,:)=C(j)*S;
end
If so, it's simply matrix multiplication:
C' * S % if C and S are row vectors
C * S' % if C and S are column vectors
If you don't know whether C and S are row vectors or column vectors, you can use a trick to turn them into column vectors, then transpose S before multiplying them:
C(:) * S(:)'
I'm not entirely clear on what you're doing - it looks like your resulting matrix will consist of length(C) rows, where the ith row is the vector S scaled by the ith entry of C (since subscripting a vector gives a scalar). In this case, you can do something like
mat = repmat(C,[1 length(S)]) .* repmat(S, [length(C) 1])
where you tile C across columns, and S down rows.
Try this:
C = 1:3
S = 1:5
mat1 = C'*S
mat2 = bsxfun(#times, C',S)
(esp. good when the function you need isn't simpler MATLAB notation)
--Loren
Try using meshgrid:
[Cm, Sm] = meshgrid(C, S);
mat = Cm .* Sm;
edit: nevermind, matrix multiplication will do too. You just need one column vector C and one row vector S. Then do C * S.