【问题标题】:Maxima: Is there any way to make functions defined within the main function be local, in a similar way to local variables?Maxima:有什么方法可以让 main 函数中定义的函数成为局部函数,类似于局部变量?
【发布时间】:2021-10-28 16:09:27
【问题描述】:

我想知道是否有任何方法可以使在主函数中定义的函数成为局部函数,类似于局部变量。例如,在这个计算标量函数梯度的函数中,

grad(var,f) := block([aux],
    aux : [gradient, DfDx[i]],
    gradient : [],
    DfDx[i] := diff(f(x_1,x_2,x_3),var[i],1),
    for i in [1,2,3] do (
        gradient : append(gradient, [DfDx[i]])
    ),
    return(gradient)
)$

已在主函数grad(var,f) 内部定义的变量gradient 在主函数外部无效,因为它位于aux 列表中。但是,我观察到函数 DfDx 尽管在 aux 列表中,但在主函数之外确实有效果。

有什么方法可以使定义在主函数中的子函数仅是本地的,就像用局部变量可以做的一样? (我知道用过之后可以kill他们,但或许还有更优雅的方式)

【问题讨论】:

    标签: maxima wxmaxima


    【解决方案1】:

    要计算梯度,我的建议是调用makelistdiff,如我的第一个答案所示。让我借此机会谈谈一些相关的话题。

    我将粘贴问题陈述中显示的grad 的定义,并用它来制作一些 cmets。

    grad(var,f) := block([aux],
        aux : [gradient, DfDx[i]],
        gradient : [],
        DfDx[i] := diff(f(x_1,x_2,x_3),var[i],1),
        for i in [1,2,3] do (
            gradient : append(gradient, [DfDx[i]])
        ),
        return(gradient)
    )$
    

    (1) Maxima 主要用于表达式而不是函数。这不会在这里造成问题,我只想说清楚。例如。一般来说,当f 是一个函数时,必须说diff(f(x), x),而不是diff(f, x),同样,integrate(f(x), ...) 而不是integrate(f, ...)

    (2) 当gradientDfdx 是局部变量时,你必须在block 的变量列表中命名它们。例如。 block([gradient, Dfdx], ...) -- Maxima 不会理解 block([aux], aux: ...)

    (3) 请注意,使用方括号而不是括号定义的函数,例如f[x] := ...而不是f(x) := ...,是Maxima中所谓的数组函数。数组函数是一个记忆函数,即如果f[x]被调用两次或多次,则返回值只计算一次,然后每次返回。有时,当函数的域包含有限集时,这是一种有用的优化。

    (4) 请记住,x_1x_2x_3 是不同的符号,彼此无关,与x[1]x[2]x[3] 无关,即使它们显示相同。我的建议是在 i 是变量时使用下标符号 x[i]

    (5) 关于建立返回值,尝试安排一次计算整个事情,而不是逐步增加结果。在这种情况下,makelist 优于 for 加上 append

    (6) Maxima 中的return 函数与其他编程语言中的行为不同;这有点难以解释。一个函数返回最后一个被计算的表达式的值,所以如果gradient是最后一个表达式,你可以写grad(var, f) := block(..., gradient)

    希望这会有所帮助,我知道它晦涩难懂且复杂。 Maxima 编程语言在实施之前并不是设计出来的,而且在 50 多年(!)之后的很长一段时间内,一些决定显然是有问题的。没关系,他们一边走一边想办法。没有一整套既定结果可以提供参考;原作者正在为今天被认为是常识的东西做出贡献。

    【讨论】:

      【解决方案2】:

      为了解决您需要在这里解决的问题,另一种计算梯度的方法是说

      grad(var, e) := makelist(diff(e, var1), var1, var);
      

      然后你可以说例如

      grad([x, y, z], sin(x)*y/z);
      

      得到

                   cos(x) y  sin(x)    sin(x) y
                  [--------, ------, - --------]
                      z        z           2
                                          z
      

      (没有内置的梯度函数;这是一个疏忽。)

      关于局部函数,请记住所有函数定义都是全局的。但是,您可以通过 local 近似本地函数定义,它保存和恢复符号的所有属性。由于函数定义是一个属性,local 具有暂时清除现有函数定义并稍后恢复它的效果。在这两者之间,您可以创建一个临时函数定义。例如

      foo(x) := 2*x;
      
      bar(y) := block(local(foo), foo(x) := x - 1, foo(y));
      
      bar(100); /* output is 99 */
      
      foo(100); /* output is 200 */
      

      但是,我不需要你使用 local -- 只需 makelist 加上 diff 就足以计算梯度。

      关于 Maxima 的作用域规则、命名和未命名函数等还有很多要说的。我明天会尝试回到这个问题。

      【讨论】:

        猜你喜欢
        • 2017-08-29
        • 1970-01-01
        • 2018-03-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多