我需要评估可变数量集合的笛卡尔积的总和。假设 f[...] 是一个多元函数,定义

p[A__set] :=  Module[{Alist, args, iterators,it},
  Alist = {A};
  i = 1;
  iterators = {it[i++], Level[#1, 1]} & /@ Alist;
  args = Table[it[i], {i, Range[Length[Alist]]}];
  Sum[f@@ args, Sequence @@ iterators ]
]

但是之后
p[set[1, 2, 3], set[11, 12, 13]]

给出错误:
Sum::vloc: "The variable Sequence@@iterators cannot be localized so that it can be assigned to numerical values."
以下黑客工作:
p[A__set] :=  Module[{Alist, args, iterators,it,TmpSymbol},
  Alist = {A};
  i = 1;
  iterators = {it[i++], Level[#1, 1]} & /@ Alist;
  args = Table[it[i], {i, Range[Length[Alist]]}];
  Sum@@TmpSymbol[f @@ args, Sequence @@ iterators ]
]

然后
p[set[1, 2, 3], set[11, 12]]

给我想要的:
f[1, 11] + f[1, 12] + f[2, 11] + f[2, 12] + f[3, 11] + f[3, 12]

我想知道为什么原来没有。

根据 belisarius 有更优雅的方法来做到这一点:
p[A__set] := Total[Outer[f, A],Length[{A}]];

最佳答案

这与评估顺序有关。请参阅 Tutorial: Evaluation 作为引用。
Sum 具有属性 HoldAll :

Attributes[Sum]



因此,只有具有某些头部的参数,例如 EvaluateSequence 或带有 upvalues 的 Symbols 才会计算。你可能认为你的论点 Sequence @@ iterators 有头部 Sequence ,但它实际上有头部 Apply :
HoldForm @ FullForm[Sequence @@ iterators]


Sum 需要匹配其声明语法的文字参数,因此您的代码失败。您可以通过几种不同的方式强制评估。可以说最透明的是添加 Evaluate :
iterators = {{a, 1, 3}, {b, 5, 7}};

Sum[a^2/b, Evaluate[Sequence @@ iterators]]



更简洁地,您可以利用 FunctionSlotSequenceApply ;由于 ApplyFunction 默认情况下都没有 HoldAll ,因此进行评估:
Sum[a^2/b, ##] & @@ iterators



然而,这两者都有一个潜在的问题:如果 ab 收到一个全局值,那么 iterators 定义中的 Symbol 将评估为这个值,导致另一个错误:
a = 0;

Sum[a^2/b, ##] & @@ iterators



相反,您可以将迭代器列表存储在 Hold 表达式中,并使用“injector pattern ”插入这些值而不进行完整的评估:
iterators = Hold[{a, 1, 3}, {b, 5, 7}];

iterators /. _[x__] :> Sum[a^2/b, x]



或者,您可以将 iterators 定义为 upvalue:
Sum[args___, iterators] ^:= Sum[args, {a, 1, 3}, {b, 5, 7}]

现在简单地:
Sum[a^2/b, iterators]



有关更多示例,请参阅我在 Keep function range as a variable 上对 Mathematica.SE 的回答,因为这个问题密切相关。具体参见我的第二个答案中的 setSpec,它可以自动创建 upvalue。

关于wolfram-mathematica - Wolfram Mathematica 中的 Sum[] 和 Sequence[],我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/20576071/

10-11 22:38
查看更多