Wolfram mathematica Wolfram Mathematica中的和[]和序列[]

Wolfram mathematica Wolfram Mathematica中的和[]和序列[],wolfram-mathematica,Wolfram Mathematica,我需要计算可变集合数的笛卡尔积的和。假设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

我需要计算可变集合数的笛卡尔积的和。假设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:“变量序列@迭代器无法本地化,因此无法将其分配给数值。”

以下黑客程序有效:

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 ]
]
然后

给我想要的:

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}]];

在Mathematica中有许多更简单的方法:

Total[Outer[f, {1, 2, 3}, {11, 12}, {a, b}],3]
(*
f[1, 11, a] + f[1, 11, b] + f[1, 12, a] + f[1, 12, b] +
f[2, 11, a] + f[2, 11, b] + f[2, 12, a] + f[2, 12, b] + 
f[3, 11, a] + f[3, 11, b] + f[3, 12, a] + f[3, 12, b]
*)

这与评估顺序有关。请参阅作为参考

Sum
具有属性
HoldAll

Attributes[Sum]
Sum[a^2/b, ##] & @@ iterators
因此,只有带有某些头的参数(如
Evaluate
Sequence
或带有upvalue的符号)才会进行计算。您可能认为您的参数
Sequence@@iterators
具有头
Sequence
,但它实际上具有头
Apply

HoldForm @ FullForm[Sequence @@ iterators]
Sum
要求文本参数与其声明的语法匹配,因此代码失败。您可以通过几种不同的方式强制执行评估。可以说,最透明的方法是添加
评估

iterators = {{a, 1, 3}, {b, 5, 7}};

Sum[a^2/b, Evaluate[Sequence @@ iterators]]
更简洁地说,您可以利用
函数
时隙序列
应用
;由于默认情况下,
应用
,或
函数
都没有
HoldAll
,因此不会进行求值:

Attributes[Sum]
Sum[a^2/b, ##] & @@ iterators
但是,这两种方法都存在潜在问题:如果
a
b
接收到全局值,
迭代器定义中的符号将计算到此值,从而导致另一个错误:

a = 0;

Sum[a^2/b, ##] & @@ iterators
Sum::itraw:原始对象0不能用作迭代器。>>

相反,您可以将迭代器列表存储在
Hold
表达式中,并使用“”插入这些值,而无需完成计算:

iterators = Hold[{a, 1, 3}, {b, 5, 7}];

iterators /. _[x__] :> Sum[a^2/b, x]
或者,您可以将
迭代器
定义为upvalue:

现在简单地说:

Sum[a^2/b, iterators]

更多的例子请参见我对的回答,因为这个问题密切相关。具体请参见我的第二个答案中的
setSpec
,它可以自动创建增值。

非常酷,谢谢
p[A\u set]:=Total[Flatten[Outer[f,A]]]
执行此任务。但这不是我问题的答案,谢谢。我不清楚是什么原因导致
Sum
变成
HoldAll
而不是
HoldFirst
。我知道了。这样迭代器中的变量就不会计算为之前分配的值。不过,它可能是留给用户来处理的。@user是的,这就是原因。我认为您会发现,如上所示强制评估比阻止评估更容易(而且不太常见)。我认为这是一个很好的设计选择,但可以在文档中更好地解释。在采用迭代器规范的其他函数中,行为类似;try:
Attributes/@{Table,Do,Product,Plot,ParametricPlot,FindRoot}
a = 0;

Sum[a^2/b, ##] & @@ iterators
iterators = Hold[{a, 1, 3}, {b, 5, 7}];

iterators /. _[x__] :> Sum[a^2/b, x]
107/15
Sum[args___, iterators] ^:= Sum[args, {a, 1, 3}, {b, 5, 7}]
Sum[a^2/b, iterators]
107/15