Conversion of symbolic expression to double without obtaining complex numbers

Hello,
I have written a function which should return the inserted values x0 of the partial derivatives of a mathematical function fun. My variables in the mathematical function are symbolic and at the end I need to convert Y, because I want to get some double values. My MATLAB function looks as follows:
function Y = patial_derivatives(fun, x0)
syms x y z P real
variables = [x y z];
for i = 1:numel(x0)
P(i) = diff(fun, variables(i));
end
Y = subs(P,{x,y,z},{x0(1),x0(2),x0(3)});
end
and I want to call the function like this:
patial_derivatives(@(x,y,z) x^ y*exp(z), [-10 1 100])
One derivative of my function obtains the logarithm and that is where it is geeting complex when I want to convert it to a double value. Does anybody have an idea how I can avoid complex numbers here?

8 Comments

"how I can avoid complex numbers here?"
Don't provide negative numbers as input to the log function.
The partial derivative of the expression w.r.t y gives a logarithmic term. Any negative input to the function will result in complex output.
syms x y z
eqn = x^y*exp(z);
Dy = diff(eqn,y)
Dy = 
subs(Dy,x,-5)
ans = 
Well, you could also provide values that result in the final output being real, but that would be a tedious task
Thanks, but that's quite difficult to realize beacuse I want to call the function in a loop. Is there any possibility to garantuee that Matlab takes the abs values for the log if I get the log inside my derivative? I know reallog but how can I implement it here without having implemented the log explicitly?
Use piecewise() to give different formulas for x negative versus positive.
But that would mean working with a different function, one that has discontinuous derivatives at x == 0.
The derivative of your function does go complex when x goes negative.
Can someone explain how this code runs at all? At this line
P(i) = diff(fun, variables(i));
fun is just an anonymous function with three dummy inputs
K>> fun
fun =
function_handle with value:
@(x,y,z)x^y*exp(z)
I'm not familiar enough the function precedence rules to understand why that call to diff resolves to the symbolic diff (note that the doc page does not include an anonymous function as an option for the first input to diff). But given that it does resolve to symbolic diff, how does diff work?
Is fun converted to symbolic expression? If so, is that documented behavior?
Is there a function that will convert an anonymous function to a symbolic expression (inverse of matlabFunction)? Seems like str2sym will do the job, but I'm not sure this usage of str2sym is documented either.
K>> f = functions(fun);
K>> f.function
ans =
'@(x,y,z)x^y*exp(z)'
K>> str2sym(f.function)
ans =
x^y*exp(z)
The posted code relies on the correspondence between the names of the dummy arguments in fun in the caller and the names of the sym variables that are local in the workspace of patial_derivatives, which can be seen if the dummy arguments to fun in the caller are changed to a,b,c, for example. Would the code be clearer (and more robust?) if that line were changed to
P(i) = diff(fun(variables(1),variables(2),variables(3)), variables(i));
If needed, the code could be generalized to accept a function of any number of arguments and return the corresponding partial derivatives.
In the call
P(i) = diff(fun, variables(i));
the first parameter might be a function handle, but the second parametter is sym . With diff() not being defined for function handles, the fact that diff() is defined for sym kicks in .
Remember that to run a method of a class, it is not necessary that a member of the class be the first parameter to the function: it is necessary instead that the class be the "dominant" class of the call.
I have read the rules about dominent classes a couple of times, but I can't say that I understand them yet.
Right, I think I saw something earlier today in another thread that talked exactly about how the second argument can determine how a function call is resolved. That's not really the surprising part; even though I don't know the resolution rules, I know they exist.
The surprising part, for me, was that diff magically transformed the function handle into a symbolic expression. Still curious if that's expected and documented behavior.
Looking at the code:
Things that are not symbolic variables or sym() class get sym() applied to them. And sym() of a function handle creates a symbolic expression.
The documented permitted values for the item to be differentiated are stricter than what is actually accepted. For example the documentation lists single and double but not any of the integer data types, but the integer types are accepted as well
diff(uint8(1:5), sym('x'))
ans = 
Thanks for pointing out that use of sym that takes in a function handle and creates a symbolic expression.
I'm almost there.
I guess we are dealing with this case from the Function Precedence Order:
7. Object functions
An object function accepts a particular class of object in its input argument list. When there are multiple object functions with the same name, MATLAB checks the classes of the input arguments to determine which function to use.
In this case, there is no object function diff for a function_handle, so we go to the object function diff for class sym. So I don't think this is a dominant class situation (but I'm probably wrong). And I don't know what happens if the argument list contains two (or more) objects of different classess that have a same-named object function, but neither class is inferior to the other. Probably goes left to right.
Anyway, now that Matlab has determined that sym->diff is to be called, it applies sym() to the first argument. Is that a rule that's always applied in classes in general? That is, if there's not an exact signature match for the object function being called, Matlab will always try to make a matching signature by applying the class constructor to the non-matching arguments? I don't do OO programming in Matlab, so I might be asking basic questions.
Regardless of how it gets done, it appears that the first argument to sym->-diff will try to get converted by sym() if it's not already sym-like (like a symfun, or symmatrix) that I assume don't need sym() applied if they are the first argument. But, if that's the case, then (as I think you're alluding to) the documentation is overly restrictive in the list of acceptable data types. Seems like it should either list all of the types that are convertible to a sym (including function_handle and uint_8) or get rid of that "single | double" and replace it with language to the effect of "anything convertible to a sym." As written, a reasonable reader might infer that a function_handle, or uint_8, should throw an error (or result in undefined behavior) because the doc explicitly calls out only single and double.

Sign in to comment.

Answers (2)

oneway, is to use a conditional statement for negative input values through abs function. But if you want to avoid complex value then simply use real function
patial_derivatives(@(x,y,z) (x)^y*exp(z), [-10 1 100])
ans = 
function Y = patial_derivatives(fun, x0)
syms x y z P real
variables = [x y z];
for k = 1:numel(x0)
P(k) = diff(fun, variables(k));
end
Y = real(subs(P,{x,y,z},{x0(1),x0(2),x0(3)}));
end
"Is there any possibility to garantuee that Matlab takes the abs values for the log if I get the log inside my derivative"
You can try this -
out = patial_derivatives(@(x,y,z) (x)^y*exp(z), [-10 1 100])
P = 
out = 
function Y = patial_derivatives(fun, x0)
syms x y z P
variables = [x y z];
for k = 1:numel(x0)
P(k) = diff(fun, variables(k));
end
%Changing log() terms to log(abs())
P = subs(P,log(variables),log(abs(variables)))
Y = subs(P,variables,x0);
end
Note that this only changes for log(), if the input has any other function that returns complex values for particular inputs, that will require additional modifiction.
You should also keep in mind what @Walter Roberson commented - "But that would mean working with a different function, one that has discontinuous derivatives at x == 0."

Asked:

on 8 Aug 2023

Edited:

on 8 Aug 2023

Community Treasure Hunt

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

Start Hunting!