hastype(z,radical) 给出不同的结果

hastype(z,radical) gives different result

我完全被这个弄糊涂了。

我注意到当到达我的一个模块深处的过程时,原始调用是从命令行生成的,它比当调用流来自另一个过程内部时达到相同的过程时工作正常从命令行调用。

我发现它归结为这一行。在调试器中,我看到了这个

 if hastype(z,radical) then
    ...

第二种情况给出false,第一种情况调用时给出true。在这两种情况下都应为真。

在调试器中,我查看 z,它说它有这个值

        1/x*sqrt(x^2*u)

现在,在调试器命令中,当我键入

        hastype(z,radical)

给出false。但是当我在命令中输入 u 的实际值时:

       hastype(1/x*sqrt(x^2*u),radical)

现在它给出 true!

此过程的所有内容都是本地的:

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

所以我不知道为什么 hastype(z,radical) 给出 false,而 hastype(1/x*sqrt(x^2*u),radical) 给出 true,而 z 本身就是 1/x*sqrt(x^2*u)

只有当我调用模块时才会发生这种情况,如上述情况 2 所述。

如您所见,一切都是本地的。 z,f,tmp 是本地的。同上调用 函数由两种情况组成。两种情况下的所有输入都相同。

实际调试的截图如下:

现在我检查

现在我按类型检查显示的实际 z 值

这似乎是范围界定问题,我不知道它是什么。可能是我所看到的,而不是它看起来的样子。

同样,当我从另一个工作的命令行调用模块时,相同的调用工作正常sheet。

两者都工作sheets(案例 1 和案例 2),使用不同的数学引擎。 (为了安全起见,我设置了 Maple 为每项工作启动新的数学引擎 sheet)

我正在寻找发生这种情况的任何建议。第二种情况下的调用过程也不使用任何全局变量。我总是从干净的内核开始(重启)。

任何提示发生了什么以及要寻找什么?或者尝试找出问题所在?

枫叶2018.1,windows10.


更新

我发现了问题。但我真的认为这是 Maple 中的一个错误。

我发现如果我使用 eval(z) 那么它在第二种情况下有效,就像这样:

 if hastype(eval(z),radical) then   

现在我明白了:

我不明白为什么我需要在那里添加 eval(),因为 Maple 在使用 for z in op(f) do 时应该自动计算 z 到它的值,然后在里面引用 z循环。

所以我的问题变成了:为什么这里需要eval()

无论如何,我有一个解决方法。但是现在这对我来说毫无意义。

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;

这里最重要的是(如您所示),z 的值涉及对 sqrt 而非 的未评估调用电源 1/2.

未求值的 sqrt 调用不是 radical 类型,尽管 它求值的 是那种类型。

首先,让我们处理在顶层(即不在任何过程主体内)对 sqrt 的未计算调用。我们首先将包含对 sqrt.

的未评估调用的表达式分配给名称 z

我们将测试名称 z 的一级评估类型,以及名称 z 的完整评估类型。

restart;
z := '1/x*sqrt(x^2*u)';

                           2
                     sqrt(x  u)
                z := ----------
                         x

z 的 1 级评估产生其值,但没有其他评估。 sqrt 调用仍未计算。

eval(z, 1); # 1-level evaluation

                         2
                   sqrt(x  u)
                   ----------
                       x

sqrt 的未评估调用是 而不是 type radical

hastype(eval(z, 1), radical);

                     false

下面是 z 的完整评估,这是顶层的默认行为。

eval(z); # full evaluation      

                     2   1/2
                   (x  u)
                   ---------
                       x

z;

                         2   1/2
                   (x  u)
                   ---------
                       x

z 传递给 hastype 现在会将完整评估传递给 hastype。也就是说,传递给 hastype 的表达式现在包含了对 1/2 的赋值,并且它被识别为属于 type radical.

hastype(z, radical);         

                     true

现在从主题 proc

的帮助页面上 "Evaluation Rules" 部分的 bullet point 中阅读这篇文章
"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."

让我们看一个与上面类似的例子,但是在一个过程中。

首先,我们将在程序中处理 z。如前所述,名称 z 被分配了包含未计算的 sqrt 调用的表达式。与顶级行为相反,在过程中,分配的本地 z 仅评估 1 级。

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

现在我们将改变处理 eval(z) 的过程,它获取包含某些东西的表达式 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

看来您正在经历记录的和预期的行为,以评估过程中分配的局部变量。那不是错误。

您只提供了代码片段,并没有准确显示传递给过程 convert_to_homog 的参数 f0, x, y, u 是什么。但是你 已经 表明本地 z1/x*sqrt(x^2*u) 不是 1/x*(x^2*u)^(1/2) 如果那是真的那么hastype(z,radical) returns false.

这不是错误

根据您当前的设置,是的,您可以将 eval(z) 传递给 hastype 并获得您期望的 true 结果。

但也许您还应该重新检查为什么 z 首先被分配了未计算的表达式。是故意的,还是之前不小心编程的?