A very strange problem

11 views (last 30 days)
Hi friends!
After spending an hour on a seemingly simple problem I was not able to figour out what is wrong and this is why
I am bothering you, Consider the following commands:
D0=1;D1=1;
f='@(dt)[(-D0)*dt^0.5+(-D0*D1)*dt^1.5/2;1/2*(-1+(1)+(2*D1+2*D0^2)*dt/2)]';
f=vectorize(f);f=str2func(f);f(1)
which gives me an error saying that "Unrecognized function or variable 'D0'.". But, when I copy the second line and run it, it works!!! To get what I mean the following is what happend on my command window exactly (see also a printscreen of my command window attached)
>> D0=1;D1=1;
f=@(dt)[(-D0).*dt.^0.5+(-D0.*D1).*dt.^1.5./2;1./2.*(-1+(1)+(2.*D1+2.*D0.^2).*dt./2)];
f=vectorize(f);
f=str2func(f);
f(1)
Unrecognized function or variable 'D0'.
Error in code2>@(dt)[(-D0).*dt.^0.5+(-D0.*D1).*dt.^1.5./2;1./2.*(-1+(1)+(2.*D1+2.*D0.^2).*dt./2)]
>> f=@(dt)[(-D0).*dt.^0.5+(-D0.*D1).*dt.^1.5./2;1./2.*(-1+(1)+(2.*D1+2.*D0.^2).*dt./2)];
>> f(1)
ans =
-1.5
1
I find this really crazy and am impatiently looking forward to hear from you.
Thanks in advance!
Babak
  4 Comments
Stephen23
Stephen23 on 14 Jan 2022
Edited: Stephen23 on 14 Jan 2022
"why matlab is like this?"
In a word: scoping.
Computers cannot read your mind (yet), they have to follow rules. Those rules include where variables/functions/whatever are visible (scoping) to other functions or operators. Although in theory a computer could look in every existing workspace for a variable, there are several major problems with this approach:
  • workspaces change, meaning that different variables come in and out of scope, leading to unpredictable code which is almost impossible to debug.
  • it would be slooooooooooow.
"I have spent some weeks and prepared extremely long function handles which are saved as text files."
Function handles store information about their scope when they are created: you can save function handles in .mat files. Converting to text or storing functions as text does not store any of this information, so your design is fundamentally lossy.
Steven Lord
Steven Lord on 14 Jan 2022
If your functions are that long, change your text files to MATLAB function files and use function handles to those files. This could also allow you to extract out common code segments into helper functions that can be called by one or more of your large function files.

Sign in to comment.

Accepted Answer

John D'Errico
John D'Errico on 14 Jan 2022
Edited: John D'Errico on 14 Jan 2022
I suppose this is a subtle problem that bears explanation.
D0=1;D1=1;
f='@(dt)[(-D0)*dt^0.5+(-D0*D1)*dt^1.5/2;1/2*(-1+(1)+(2*D1+2*D0^2)*dt/2)]';
That does NOT create a function handle named f. It is a string. Next, you do this:
f=vectorize(f)
f = '@(dt)[(-D0).*dt.^0.5+(-D0.*D1).*dt.^1.5./2;1./2.*(-1+(1)+(2.*D1+2.*D0.^2).*dt./2)]'
That just produces a new string. Still not a function.
f=str2func(f)
f = function_handle with value:
@(dt)[(-D0).*dt.^0.5+(-D0.*D1).*dt.^1.5./2;1./2.*(-1+(1)+(2.*D1+2.*D0.^2).*dt./2)]
So finally, f exists as a function handle. WHEW!
f(1)
Unrecognized function or variable 'D0'.

Error in solution>@(dt)[(-D0).*dt.^0.5+(-D0.*D1).*dt.^1.5./2;1./2.*(-1+(1)+(2.*D1+2.*D0.^2).*dt./2)]
But what happened? str2func creates a function handle, returning a result. But str2func does not have D0 in its workspace. So when you try to use f, in the form of f(1), things fail. f does not know the value of D0 or D1, because they do not exist in the workspace of the function str2func.
However, if I do this:
f= @(dt)[(-D0)*dt^0.5+(-D0*D1)*dt^1.5/2;1/2*(-1+(1)+(2*D1+2*D0^2)*dt/2)]
f =
function_handle with value:
@(dt)[(-D0)*dt^0.5+(-D0*D1)*dt^1.5/2;1/2*(-1+(1)+(2*D1+2*D0^2)*dt/2)]
f(1)
ans =
-1.5
1
now f works, because D0 and D1 were available to f when I created that function handle. It encapsulates them in the workspace internal to the function handle, and all is good. However, f is not "vectorized", as a function of the variable dt.
Anyway, a problem exists, because f returns a vector. you would need to carefully define what that result will be when dt is itself a vector or an array. And as importantly, suppose dt was a row vector, versus a column vector? That code for f, if you blindly throw the vectorize function at it, will produce some screwy results. Magical functions like vectorize are not that intelligent.
Instead, it is far better to vectorize the code yourself. So I might do this, in a way that is insensitive to the shape of dt as a row or column vector.
fvect = @(dt)[(-D0)*dt(:).^0.5+(-D0*D1)*dt(:).^1.5/2 , 1/2*(-1+(1)+(2*D1+2*D0^2)*dt(:)/2)].'
fvect(1)
ans =
-1.5
1
fvect(1:5)
ans =
-1.5 -2.8284 -4.3301 -6 -7.8262
1 2 3 4 5
fvect((1:5)')
ans =
-1.5 -2.8284 -4.3301 -6 -7.8262
1 2 3 4 5
So fvect has been carefully vectorized to produce a result that is consistent with f when called with scalar input, but when called with a vector input, it produces a 2xn array.
Finally, because fvect was constructed directly, it fully encapsulates the values of D0 and D1 as they were found in the workspace when fvect was created.
But expecting vectorize to successfully do that is a bit too much, certainly to know the values of D0 and D1.
  5 Comments
John D'Errico
John D'Errico on 14 Jan 2022
Edited: John D'Errico on 14 Jan 2022
Yes it does fix your problem, as long as you put a semi-colon on the line! I left off the semi-colon at the end of the line just so you could see the result is indeed a function handle.
When you add a semi-colon to the end of the line, it prevents the display from going to the command window. This will now be fast, since the time spent lies in MATLAB formatting the results for display, in scrolling the command window, etc.
Mohammad Shojaei Arani
Mohammad Shojaei Arani on 14 Jan 2022
Thanks Torsten for your precious time!

Sign in to comment.

More Answers (2)

KSSV
KSSV on 14 Jan 2022
f='@(D0,D1,dt)[(-D0)*dt^0.5+(-D0*D1)*dt^1.5/2;1/2*(-1+(1)+(2*D1+2*D0^2)*dt/2)]';
f=vectorize(f);
f=str2func(f);
D0=1;D1=1;dt=1 ;
f(D0,D1,dt) % you need to input three variables to the function
ans = 2×1
-1.5000 1.0000
  3 Comments
Matt J
Matt J on 14 Jan 2022
Edited: Matt J on 14 Jan 2022
Yes, but that can be achieved with a very small modification.
f='@(D0,D1,dt)[(-D0)*dt^0.5+(-D0*D1)*dt^1.5/2;1/2*(-1+(1)+(2*D1+2*D0^2)*dt/2)]';
f=vectorize(f);
f=str2func(f);
D0=1;D1=1;;
f=@(dt)f(D0,D1,dt);
f(1)
ans = 2×1
-1.5000 1.0000
Mohammad Shojaei Arani
Mohammad Shojaei Arani on 15 Jan 2022
This is a clever and beautiful solution! (I wish if matlab could use AI techniques and tell me "did you want this?" so that I would not waste a lot of time for such things)
Trying to understand why your therapy works. Perhaps, the clue is that in your solution D0 and D1 are defined after the command f=str2func(f) while in my case if was before.

Sign in to comment.


Matt J
Matt J on 14 Jan 2022
An alternative solution is to download afslim() from,
D0=1;D1=1;
f='@(dt)[(-D0)*dt^0.5+(-D0*D1)*dt^1.5/2;1/2*(-1+(1)+(2*D1+2*D0^2)*dt/2)]';
f=afslim(vectorize(f),D0,D1)
f = function_handle with value:
@(dt)[(-D0).*dt.^0.5+(-D0.*D1).*dt.^1.5./2;1./2.*(-1+(1)+(2.*D1+2.*D0.^2).*dt./2)]
f(1)
ans = 2×1
-1.5000 1.0000

Categories

Find more on Loops and Conditional Statements in Help Center and File Exchange

Community Treasure Hunt

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

Start Hunting!