Why are predefined variables not shown with their value in function handles?
Asked Answered
C

1

5

In MATLAB R2020b I have the following code:

f=@(x) x.^2;
y=2;
g=@(x) f(x).*y

and the output is

g = function_handle with value: @(x)f(x).*y

But y = 2, so I would expect the output to be @(x)f.*2. Is this how its supposed to work or a bug? And can I display it as f.*2 rather than f.*y?

Callous answered 24/6, 2021 at 11:59 Comment(11)
I'd say that that's how it's supposed to work, but only The MathWorks themselves can tell you why. As to chaging the display: you'd need to overload the default disp() method for function handle classes, i.e. you'd need to modify the MATLAB source code for this class directly. It might be impossible, e.g. if the code is pre-compiled and/or obfuscated, and even if possible, I'd recommend against modifying MATLAB source files. You might be able to write a wrapper function that's called instead on disp() calls for function handles.Lillith
Just to verify what happens to the y: what happens if you do y = 3;h=@(x) f.*y and then compare the output with that of g? and of course: what happens then for g(2) and h(2)? Are the outputs the same, i.e. did the value of y inside g change, or are they different?Lillith
Actually I meant to type g(x)=@(x)f(x).*y, as is edited. Then g(2) gives me 8 and h(2) gives 12. So it works when I put in the argument. But I need to create an array of Legendre polynomials (by recursion), P_=cell(1,N+1); P_{1}=@(u_) 1; P_{2}=@(u_) u_; for n=1:N, P_{n+2}=@(u_)((n+1)*@(u_)P_{n+1}(u_)-n*@(u_)P_{n}(u_))/(2*n+1); end and it never progresses because each cell has n but not its value in the loop. Any ideas on this?Callous
“it never progresses because each cell has n but not its value in the loop” — I think that does work, you just can’t see it from the displayed function. Evaluate them to verify. But anyway it’s much easier to represent polynomials using a vector with the constant factors, see here.Passkey
OK thanks. I actually it does output a number for a variable input: P_{3}(4) gives `` 2.3333. But I still find it a problem that P_{3}`` gives `` function_handle with value: @(u_)((n+1)*P_{n+1}(u_)-n*P_{n}(u_))/(2*n+1)``, because n=4. This make the code difficult to check analytically.Callous
Indeed, it’s hard to check and it’s also highly inefficient. Do use the representation I recommend, it fixes both issues.Passkey
@CrisLuengo, I intend to integrate over the Legendre polynomials numerically. Is that possible with the representation you suggest?Callous
Yes, much more efficiently. Evaluating that polynomial representation is just a dot product, compared to calling an anonymous function that calls two anonymous functions, which call four more anonymous functions...Passkey
K I see how the method I was using is inefficient. But function handles can be used in functions like integral and quadgk which apply some fancy quadrature. Is this possible with the vector polynomials?Callous
Please tag me in your comments with @Cris to notify me of your comment. Otherwise I only see it by chance... You can create an anonymous function that calls polyval. The approach would allow computing the polynomial factors once, when you construct it, rather than every time you evaluate the polynomial.Passkey
And it's not just about the size of the variables: the type of y could have been anything. And Matlab does not have a generalized method of formatting arbitrary values as literal expressions. (mat2str only works on basic primitive types.) Plus what if y occurred several times in the function's code? Easier to understand if it's a variable. Finally, if y is a handle object, its value is actually mutable, and could change between subsequent calls on your anonymous function.Brochette
C
7

When you create the function handle g = @(x) f(x).*y, the current values of the variables f and y get "frozen" into g's definition, as discussed in the documentation.

To inspect the actual values of f and y that g uses, you can call functions as follows:

>> info = functions(g); disp(info)
            function: '@(x)f(x).*y'
                type: 'anonymous'
                file: ''
           workspace: {[1×1 struct]}
    within_file_path: '__base_function'

Specifically, see the workspace field:

>> disp(info.workspace{1})
    f: @(x)x.^2
    y: 2
Christachristabel answered 24/6, 2021 at 15:23 Comment(1)
Nice. And as Andras commented in chat: "It makes sense that a closed variable that's a 5000-sized matrix will not be substituted". Copying the variable into the function handle allows for lazy copying.Passkey

© 2022 - 2024 — McMap. All rights reserved.