Nasser
Nasser

Reputation: 13173

hastype(z,radical) gives different result

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:

Mathematica graphics

Now I check

Mathematica graphics

Now I check by type the actual z value shown

Mathematica graphics

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:

Mathematica graphics

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

Answers (1)

acer
acer

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

Related Questions