Substitute vector of values for symbolic variable within a function?

So, using a really long Taylor expansion, I managed to generate a long function of 5 symbolic variables in Matlab, but now I want to replace one of those variables with a vector, so that the function outputs one value when evaluated on values of the other symbolic var.s and on any specific index of said vector.
For some context; normally, I can create a function of symbolic and vector values like this.
fun = @(x,data) 1/sqrt(2*pi) * exp(-(data(:,2)-(x(1)+x(2)*data(:,1)).^2)/2);
Where data happens to be a two-column vector.
For my current function to replace a var with a data vector, I tried doing
pX = subs(pX, "old var.", data(1:end))
but it just keeps running for forever, making me think something is wrong. How would I do this, guys? I would appreciate any help in this matter.

Réponses (1)

I advise against assigning a numeric value to a variable that has been used in a symbolic expression. The chances are too high that you will mix up whether the variable is symbolic or numeric.
People tend to expect that when they assign a numeric value to a variable that has been used in a symbolic expression, that suddenly the expression will start evaluating as if the symbol had been assigned the numeric value, but that is not how it works -- just like when you do
a = 1;
b = a + 1;
a = 2;
then b does not suddenly become 2+1: the value of a at the assignment is copied and used in the assignment. Just so,
syms a
b = a + 1;
a = 2;
the value of a at the time of the assignment is copied and used in b.
What I recommend is that you use a different variable name to hold the numeric value, and then subs() that in. So perhaps assign to Data instead of to data, and then
subs(Px, data, Data)
the (1:end) is redundant by the way.
It is possible for a subs() to take a long time to execute. The symbolic engine is not always able to get closed form solutions for an expression involving a symbolic variable, but when you substitute in a particular numeric value, then it might be able to create the closed form solution -- which could take a lot of time. For example, the exact value might provide enough information to perform a numeric integral, or might provide enough information to be able to find roots (which can be fairly expensive when a floating point exponent gets converted to a rational values and you have to suddenly find 2^53 complex roots of an expression...)

10 commentaires

Could you elaborate on your solution with creating a different variable data instead of what I did? I am confused by what you did there. The reason I need to be able to do this is because, in the end, I am going to feed the function into an optimization routine over the other variables, and there needs to be some data within the function, namely the variable that becomes a vector, to evaluate the function over. I have optimized this way in the past, but never needed to perform complex symbolic transformations on my function prior to optimization, hence my attempt at 'subbing in' my data.
You wrote,
"For my current function to replace a var with a data vector, I tried doing
pX = subs(pX, "old var.", data(1:end))"
and I am saying, make sure that "old var." is not data -- do not create a symbolic expression based upon
syms data
pX = ... something involving data ...
and then try to do
data = some numeric vector
pX = subs(pX, sym('data'), data);
Instead use a different variable name for the numeric and the symbolic components, such as
syms data
pX = ... something involving data ...
Data = some numeric vector
pX = subs(pX, data, Data);
"so that the function outputs one value when evaluated on values of the other symbolic var.s and on any specific index of said vector"
Much of the time you should instead pass the entire data matrix as a parameter, and then at execution time, retrieve the appropriate indexed entry and complete the calculation. The time to not do that would be if you are intending to create an array of symbolic expressions in s or an array of function handles, one for each entry in data, and pull out one of them according to an index, and then evaluate that function handle with a whole bunch of different s values, and evaluating with a specific numeric data allows pre-calculation of expensive calculations. For example if your expression happened to be something along the lines of
pX = s + vpaintegral(besselj(x, 1/4), x, 0, data)
then the int() can be completed ahead of time knowing the specific numeric values for data, and besselj is expensive enough to make doing this pre-calculation worth-while.
If, on the other hand, your expression happened to be something along the lines of
pX = vpaintegral(besselj(s+x, 1/4), x, 0, data)
then knowing the exact numeric value for the data probably makes no difference to the calculation time: you would have to do a bunch of research to find a way to pre-calculate anything here that might allow you to complete the integral more quickly when you finally know a numeric s value.
I also recommend that you carefully read over the matlabFunction documentation, paying particular attention to the use of the 'vars' option when used with a cell array, and that you read over http://www.mathworks.com/help/matlab/math/parameterizing-functions.html
I feel like you understand my issue more now, because I agree completely regarding your advice on replacing the old var. with a new numeric one. Thanks for the link, which I'll also look into as I definitely need more experience in functions.
Precisely, the function I have is this,
-(274877906944*exp(-(2*(x^(1/2) - xs^(1/2))^2)/(c^2*h))*((h^(1/2)*(12288*a^2*b^2 - 12288*a*b*c^2 + 2304*c^4))/xs^(3/2) + (49152*b*xs^(1/2))/h^(1/2) + (- 36864*c^2 + 49152*a*b)/(h^(1/2)*x^(1/2)) - (- 12288*c^2 + 49152*a*b)/(h^(1/2)*xs^(1/2)) - 12288*b^2*h^(1/2)*xs^(1/2) + 2048*b^3*h^(3/2)*xs^(1/2) + (h^(3/2)*(- 6144*a^3*b^3 + 13824*a^2*b^2*c^2 - 8832*a*b*c^4 + 1440*c^6))/xs^(5/2) - (h^(1/2)*(12288*a^2*b^2 - 12288*a*b*c^2 + 2304*c^4))/(x^(1/2)*xs) + (12288*b^2*h^(1/2)*xs)/x^(1/2) - (2048*b^3*h^(3/2)*xs)/x^(1/2) + (512*b^2*h^(3/2)*(- c^2 + 4*a*b))/x^(1/2) - (512*b^2*h^(3/2)*(- c^2 + 4*a*b))/xs^(1/2) + (384*b*h^(3/2)*(16*a^2*b^2 - 16*a*b*c^2 + 3*c^4))/xs^(3/2) - (h^(3/2)*(- 6144*a^3*b^3 + 13824*a^2*b^2*c^2 - 8832*a*b*c^4 + 1440*c^6))/(x^(1/2)*xs^2) - (49152*b*xs)/(h^(1/2)*x^(1/2)) - (384*b*h^(3/2)*(16*a^2*b^2 - 16*a*b*c^2 + 3*c^4))/(x^(1/2)*xs)))/(16933275245376783*c^3)
and I'm trying to replace the var. x with data, but when I run
pX = subs(pX,x,data)
I get a behemoth of an output (I won't even paste it), not simply the previous equation with one variable changed to a vector, but some weird evaluation Matlab is doing. This is what I am having an issue with.
When I test with some random data, I get what I expect, which is to say a large vector.
You have to understand that
pX = subs(pX, x, data)
is the same as
pX = zeros(size(data), 'sym');
for K = 1 : numel(data)
pX(K) = subs(pX, x, data(K));
end
so each entry of pX will repeat the entire expression pX except with x substituted as one particular numeric value.
You will not get
-(17179869184.*exp(-(2.*(data.^(1./2) - xs.^(1./2)).^2)./(c.^2.*h)).*((h.^(1./2).*(2304.*c.^4 + 12288.*a.^2.*b.^2 - 12288.*a.*b.*c.^2))./xs.^(3./2) + (49152.*b.*xs.^(1./2))./h.^(1./2) + (49152.*a.*b - 36864.*c.^2)./(h.^(1./2).*data.^(1./2)) - (49152.*a.*b - 12288.*c.^2)./(h.^(1./2).*xs.^(1./2)) - 12288.*b.^2.*h.^(1./2).*xs.^(1./2) + 2048.*b.^3.*h.^(3./2).*xs.^(1./2) + (h.^(3./2).*(1440.*c.^6 - 6144.*a.^3.*b.^3 + 13824.*a.^2.*b.^2.*c.^2 - 8832.*a.*b.*c.^4))./xs.^(5./2) - (h.^(1./2).*(2304.*c.^4 + 12288.*a.^2.*b.^2 - 12288.*a.*b.*c.^2))./(data.^(1./2).*xs) + (12288.*b.^2.*h.^(1./2).*xs)./data.^(1./2) - (2048.*b.^3.*h.^(3./2).*xs)./data.^(1./2) + (512.*b.^2.*h.^(3./2).*(4.*a.*b - c.^2))./data.^(1./2) - (512.*b.^2.*h.^(3./2).*(4.*a.*b - c.^2))./xs.^(1./2) + (384.*b.*h.^(3./2).*(3.*c.^4 + 16.*a.^2.*b.^2 - 16.*a.*b.*c.^2))./xs.^(3./2) - (h.^(3./2).*(1440.*c.^6 - 6144.*a.^3.*b.^3 + 13824.*a.^2.*b.^2.*c.^2 - 8832.*a.*b.*c.^4))./(data.^(1./2).*xs.^2) - (49152.*b.*xs)./(h.^(1./2).*data.^(1./2)) - (384.*b.*h.^(3./2).*(3.*c.^4 + 16.*a.^2.*b.^2 - 16.*a.*b.*c.^2))./(data.^(1./2).*xs)))./(1058329702836049.*c.^3)
except with data replaced by a numeric vector of the data elements. You do not get out a single expression that happens to be vector valued: you get back a vector of expressions.
It might help to understand that the symbolic engine has no ability to have a single symbol stand in for an array (or vector): it can only have an array (or vector) in which every symbol is considered scalar. So this behaviour of expanding out expressions is hardwired in the symbolic engine.
Now I know why I get a huge answer, it's just the old function with the current index of the new vector changing it each time. In that case, is there any workaround for getting a single expression that's vector-valued? If subs can't do it, then there must be something else.
Yes, there is a way to get that. You can use the facilities of the symbolic engine to create a whole new DOM (domain) along with all associated operations on the domain, including some operations not presently defined, making sure that you program in non-commutative and non-transitive operations into the symbolic engine. And then you create a new MATLAB class, possibly derived from sym (but I am not sure that will work) that you code everything in terms of, with the new class differing from the current sym class in how it converts the new DOM objects to display them, but more importantly differing in how it preserves non-commutative properties such A*B not being the same as B*A. The current symbolic interface converts all user entered .* and ./ and .^ to their non-dot version because it knows that every symbol is scalar, but your version will need to preserve the distinction because it needs to have the correct operation in place in case you substitute a vector or array for a symbol.
Yes, this is a lot of work. Your question was whether it was possible somehow, not whether it was practical. Don't forget that you will need to program even the meaning of derivatives and integration and factoring and simplification...
This seems strange to me. If I wanted to I could copy the whole outputted equation out of Matlab, manually replace every variable in a text editor, including the one I want to now be a vector of values, reinput that into matlab, and define a new function by
fun = @(a,b,c,x,data) = ... whole new function with manual edits ...
and that would get the job done I want. How is there not a process to automate this?
If you are headed towards that then you should use matlabFunction(), especially with the 'file' version with the default of optimization left on.
Sorry for an maybe unrelated question.
Is it possible to replace a symbolic function with a vector? For example, use syms theta(t) for representing a theta of time, then do the partial derivative and come out with an equation, now i need to solve the equation but there seems to be some difficulties.
The purpose is to solve the Lagrange equation, but there are six symbolic function in it. I cannot use "dsolve" for these six equation (with conditions but it says that the number of indeterminates can't match with the equations or it would come out with an empty answer) . I also tried assumption (assume some of the symbolic variables to be bound in a range, i.e. 1 <= theta(t) <= 5, and it says that it cannot assume symbolic function, only symbolic variables or expressions) and substitution (subs theta(t) with a vector composed of values, run the equation again and it didn't change). There are first-order and second-order differential of six symbolic function in those six equations.
I'm not sure which step i go wrong. Hope to get some positive response. Thanks!
Yu Tsai Chen,
Please start a new Question for that, posting your equations and any relevant constraints.

Connectez-vous pour commenter.

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by