Reputation: 13173
I am completely baffled by this.
I noticed when a proc deep inside one of my modules is reached, where the original call was generated from command line, it works correctly than when the same proc is reached when the call flow is originated from inside another proc which is called from the command line.
I found it comes down to this one line. In the debugger, I see this
if hastype(z,radical) then
...
This gives false in the second case, and it gives true when called in the first case. It should give true in both cases.
In the debugger, I look at z, it says it has this value
1/x*sqrt(x^2*u)
Now, in the debugger command, when I type
hastype(z,radical)
It gives false
. But when I type the actual value of u
into the command:
hastype(1/x*sqrt(x^2*u),radical)
Now it gives true
!
Everything is local to this proc:
dsolve_step:-dsolve_step_homog:-convert_to_homog := proc(f0, x, y, u)
local f, z, tmp;
1 f := f0;
2 f := subs(y = u*x,expand(f));
3 for z in op(f) do
4 ! if hastype(z,radical) then ##<=======
5 tmp := sqrt(collect(z^2,x));
6 f := subs(z = tmp,f)
end if
end do;
7 return simplify(f)
end proc
So I have no idea why hastype(z,radical)
gives false, and hastype(1/x*sqrt(x^2*u),radical)
gives true, when z
itself is 1/x*sqrt(x^2*u)
.
And this happens only when I call the module as in case 2 described above.
As you can see, everything is local. z,f,tmp
are local. Same call the the above
function is made from both cases. All the input is the same in both cases.
Here are screen shots from the actual debugging:
Now I check
Now I check by type the actual z value shown
It seems like scoping issue, which I can't figure what it is. May be what I am looking at, is not what it appears to be.
Again, the same call works OK when I call the module from the command line, from another worksheet.
Both worksheets (case 1 and case 2), use different math engines. (I set up Maple to start new math engine for each work sheet to be safe)
I am looking for any suggestion why this happens. The calling proc in the second case, does not use any global variables either. I always start from clean kernel (restart).
Any hint what is going on and what to look for? Or what to try to find what is the problem?
Maple 2018.1, windows 10.
Update
I found the problem. But I really think this is a bug in Maple.
I found if I use eval(z)
then it works in the second case, like this:
if hastype(eval(z),radical) then
Now I get true:
I do not see why I need to add eval()
there, since Maple should automatically evaluate z
to its value when using for z in op(f) do
and then reference z
inside the loop.
So my question has changed to: Why is eval()
needed here?
Any way, I have a workaround for this. But this makes no sense to me now.
convert_to_homog:=proc(f0,x,y,u)
local f,z,tmp;
f:=f0;
f:=subs(y=u*x,expand(f));
#this below can give wrong answer sometimes. It tries to
#change 1/X*sqrt(x^2) to sqrt(1)
#by moving x under the sqrt. But this is valid only when x>0
# i..e 1/x => sqrt(1/x^2) only when x>0
#keep it for now, until I implement exact solver.
for z in op(f) do
if hastype(eval(z), radical) then
tmp:=sqrt(collect(z^2,x));
f:=subs(z=tmp,f);
fi;
od;
return(simplify(f));
end proc;
Upvotes: 0
Views: 90
Reputation: 7271
Of key importance here is that (as shown by you), the value of z
is involves an unevaluated call to sqrt
and not something to power 1/2
.
The unevaluated sqrt
call is not of type radical
, though what it evaluates to is of that type.
First, let's deal with such an unevaluated call to sqrt
at the top-level (ie. not inside any procedure body). We first assign to name z
the expression containing the unevalated call to sqrt
.
We'll test the type of 1-level evaluation of name z
, as well as the full evaluation of the name z
.
restart;
z := '1/x*sqrt(x^2*u)';
2
sqrt(x u)
z := ----------
x
1-level evaluation of z
produces its value, but with no other evaluation. The sqrt
call remains unevaluated.
eval(z, 1); # 1-level evaluation
2
sqrt(x u)
----------
x
The unevaluated call to sqrt
is not of type
radical
.
hastype(eval(z, 1), radical);
false
Now here is the full evaluation of z
, which is default behavior at the top-level.
eval(z); # full evaluation
2 1/2
(x u)
---------
x
z;
2 1/2
(x u)
---------
x
Passing z
to hastype
now passes the full evaluation to hastype
. That is, the expression passed to hastype
now contains something to power 1/2
, and it recognized as being of type
radical
.
hastype(z, radical);
true
Now read this, from a bullet point in the section "Evaluation Rules" on the help-page for TOPIC proc
,
"Within a procedure, during the execution of its
statementSequence, local variables have single level
evaluation. This means that using a variable in an
expression will yield the current value of that variable,
rather than first evaluating that value."
Let's look at a similar example as above, but within a procedure.
First, we'll deal with z
in the procedure. As earlier, the name z
is assigned the expression containing the unevaluated sqrt
call. In contrast to the top-level behavior, within the procedure the assigned local z
is evaluated only 1-level.
restart;
f := proc( f0 )
local z;
lprint( f0 );
z := f0;
lprint( z );
hastype(z, radical);
end proc:
f( '1/x*sqrt(u*x^2)' );
1/x*sqrt(u*x^2)
1/x*sqrt(u*x^2)
false
And now we'll alter the procedure to deal with eval(z)
, which gets the expression containing something to power 1/2
.
restart;
f := proc( f0 )
local z;
lprint( f0 );
z := f0;
lprint( eval(z) );
hastype(eval(z), radical);
end proc:
f( '1/x*sqrt(u*x^2)' );
1/x*sqrt(u*x^2)
1/x*(u*x^2)^(1/2)
true
So it appears that you are experiencing the documented and intended behavior for evaluation of assigned local variables within a procedure. That is not a bug.
You have only supplied a fragment of the code, and have not shown exactly what are the arguments f0, x, y, u
passed to procedure convert_to_homog
. But you have shown that local z
is 1/x*sqrt(x^2*u)
and not 1/x*(x^2*u)^(1/2)
and if that is true then it is not a bug that hastype(z,radical)
returns false
.
With you current set up, yes, you can pass eval(z)
to hastype
and get the true
result you expect.
But perhaps you should also re-examine why z
is being assigned the unevaluated expression in the first place. Is that deliberate, or because of accidental programming earlier?
Upvotes: 1