【问题标题】:Defining a function with an optional value that is by default a function of another paramether of the function in mathematica定义具有可选值的函数,默认情况下,该函数是mathematica中函数的另一个参数的函数
【发布时间】:2011-11-15 16:26:24
【问题描述】:

我正在尝试定义一个接收矩阵的函数,当它的维度未作为输入提供时,在可选参数 d 中计算这些维度

这不起作用,但给你的想法(选项参数需要是常量):

Options[DimM] = {d -> Dimensions[A]};
DimM[A_?MatrixQ, OptionsPattern[]] := OptionValue@d;

确实,简单的方法是输入一个不可能的值,然后在函数 def 中放入一个 if 条件

Options[DimM] = {d -> 0};
DimM[A_?MatrixQ, OptionsPattern[]] :=If[OptionValue@d==0,Dimensions[A],OptionValue@d]

我怎样才能最有效地做到这一点?

【问题讨论】:

    标签: wolfram-mathematica


    【解决方案1】:

    这并不是对您的“简单方式”的真正改进,但对于许多内置的 Mathematica 函数,符号 Automatic 被用作“不可能的值”。例如:

    Options[DimM] = {d -> Automatic};
    DimM[A_?MatrixQ, OptionsPattern[]] := OptionValue[d] /. Automatic->Dimensions[A]
    
    DimM[RandomInteger[10, {2, 2}]]
    (* {2, 2} *)
    
    DimM[RandomInteger[10, {2, 2}], d -> {5, 5}]
    (* {5, 5} *)
    

    【讨论】:

    • 谢谢。如果我有多个可选参数怎么办?我如何命名它们?
    • 您可以使用Automatic 为所有这些。然后,在函数内部依次引用每个选项:a = OptionValue[A] /. Automatic -> defaultA; b = OptionValue[B] /. Automatic -> defaultB.
    • 对对对!如果提供了 d 的值,我们是否仍然计算Dimensions[A]?我认为不会,因为如果在 OptionValue[d] 中未找到 Automatic,则不会激活替换规则。我错过了吗?如果在上下文中我已经知道并可以传递它,我的目标是避免计算Dimensions[A]。
    • @Phil 正如所写,该解决方案在任何情况下都会计算Dimensions。为了避免在这种方法中计算Dimensions,您可以简单地使用延迟规则:Automatic :> defaultA
    • 如果选项值不是Automatic,则不会激活替换规则是正确的。但是,正如我所写的,Dimensions[A] 将始终被评估。为了避免不必要的计算,替换规则必须写成延迟规则,即Automatic :> Dimensions[A]
    【解决方案2】:

    对于您的原始表述,@WReach 给出了一个很好的答案。但是,重新考虑您的设计可能是有意义的:请注意,d 的值(取决于输入参数)无论如何。可选参数正是为此而设计的 - 可选。在您的情况下,默认参数似乎更合适。您可以使用Automatic 进行设置,类似于@WReach 的建议:

    dimMAuto[a_?MatrixQ, d_: Automatic] :=
         If[d === Automatic, Dimensions[a], d];
    

    要在代码中的多个位置使用它,您需要引入一个辅助变量或常量(使用WithModule)来存储这个值。作为替代方案,您还可以使用以下代码:

    Module[{dims},
      dimM[a_?MatrixQ, d_: dims] :=
          Block[{dims = Dimensions[a]}, 
              d]
    ] 
    

    它的优点是您可以在函数体的任何地方使用相同的原始参数d。这里发生的事情相当重要:Module 用于生成唯一符号,然后将其作为 d 的默认值并用于动态计算尺寸。请注意,Block 本地化的不是符号 dims,而是由 Module 生成的唯一符号,如 dims$77542ModuleBlock 的这种组合使这种技术完全安全。使用示例:

    In[1466]:= dimM[IdentityMatrix[3],{1,1}]
    Out[1466]= {1,1}
    
    In[1467]:= dimM[IdentityMatrix[3]]
    Out[1467]= {3,3}  
    

    我认为ModuleBlock 的这种组合是一种有趣的技术,它可能会找到其他用途。从本质上讲,它是通过词法作用域(或更准确地说,它在 Mathematica 中的模仿)使动态作用域变得安全的一个版本——因为动态作用域的主要危险之一是同名的动态本地化符号的无意冲突。

    关于一个不相关的问题 - 最好不要以大写字母开头变量和函数,因为它们可能会与系统符号发生冲突。

    【讨论】:

    • 这很深!我唯一关心的是效率。似乎模块/块组合计算维度 [a] 是否提供了 d 的值,这正是我试图不做的事情。我错过了什么吗?
    • @Phil 是的,你是对的。在Dimensions 的情况下,开销可能不是很重要,但如果这对你来说只是一个玩具例子,我明白你的意思。你可以让它有条件地计算函数,代价是让代码更难看:Module[{dims},dimM[a_?MatrixQ, d_: dims] := Block[{dims}, If[d===dims,dims = Dimensions[a]]; function-body]]。也许,这有点破坏目的,但你仍然有在身体各处使用原始参数d 的优势。您还可以编写一个宏来抽象出Module-Block 部分。
    • 如果我理解正确的话,BlockModule 值中的使用是通过一个本地的、唯一的 var 创建一个动态默认值,该变量可以根据需要获取其值。聪明的。 +1。
    • @rcollyer 是的,就是这样。仅使用Block[{dims},... 是危险的,因为原则上函数的主体可能会使用相同的全局符号dims 用于某些不相关的目的,在由主体评估产生的函数调用链中(dims 不一定在词法上存在在身体里)。这是动态作用域的一个主要问题。但是,通过使用Module,我们确保所讨论的动态范围符号是唯一的,并且不可能与其他符号发生冲突。 AFAICT,这种动态范围的变化更安全。我之前用过几次。
    • 又一篇有趣的论文,Leonid。 :-)
    猜你喜欢
    • 1970-01-01
    • 2016-05-03
    • 1970-01-01
    • 1970-01-01
    • 2023-03-27
    • 2020-06-11
    • 2011-08-26
    • 1970-01-01
    • 2019-08-21
    相关资源
    最近更新 更多