Wolfram Mathematica 中的 Sum[] 和 Sequence[] [英] Sum[] and Sequence[] in Wolfram Mathematica

查看:41
本文介绍了Wolfram Mathematica 中的 Sum[] 和 Sequence[]的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要计算一组可变数量的笛卡尔积的总和.假设 f[...] 是一个多元函数,定义

p[A__set] := Module[{Alist, args, iterators,it},阿里斯特 = {A};我 = 1;迭代器 = {it[i​​++], Level[#1, 1]} &/@ 一个列表;args = Table[it[i], {i, Range[Length[Alist]]}];Sum[f@@ args, 序列@@ 迭代器]]

然后

p[set[1, 2, 3], set[11, 12, 13]]

给出错误:Sum::vloc: "变量 Sequence@@iterators 不能被本地化,因此它可以被分配给数值."

以下 hack 有效:

p[A__set] := Module[{Alist, args, iterators,it,TmpSymbol},阿里斯特 = {A};我 = 1;迭代器 = {it[i​​++], Level[#1, 1]} &/@ 一个列表;args = Table[it[i], {i, Range[Length[Alist]]}];Sum@@TmpSymbol[f @@ args, Sequence @@ 迭代器]]

然后

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

解决方案

这与求值顺序有关.请参阅教程:评估作为参考.

Sum 具有属性 HoldAll:

属性[总和]

<块引用>

{HoldAll, Protected, ReadProtected}

因此,只有具有某些头部的参数,例如 EvaluateSequence 或带有 upvalues 的 Symbols 才会计算.您可能认为您的参数 Sequence @@ iterators 具有头部 Sequence,但它实际上具有头部 Apply:

HoldForm @ FullForm[序列@@迭代器]

<块引用>

Apply[序列,迭代器]

Sum 需要与其声明的语法相匹配的文字参数,因此您的代码会失败.您可以通过几种不同的方式强制评估.可以说最透明的是添加Evaluate:

iterators = {{a, 1, 3}, {b, 5, 7}};Sum[a^2/b, Evaluate[序列@@迭代器]]

<块引用>

107/15

更简洁地,您可以利用FunctionSlotSequenceApply;由于 ApplyFunction 在默认情况下都没有 HoldAll:

Sum[a^2/b, ##] &@@迭代器

<块引用>

107/15

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

a = 0;Sum[a^2/b, ##] &@@迭代器

<块引用>

Sum::itraw:原始对象 0 不能用作迭代器.>>

相反,您可以将迭代器列表存储在 Hold 表达式中并使用注入器模式" 插入这些值而不进行完整的评估:

iterators = Hold[{a, 1, 3}, {b, 5, 7}];迭代器/._[x__] :>总和[a^2/b, x]

<块引用>

107/15

或者,您可以将 iterators 定义为 upvalue:

Sum[args___, iterators] ^:= Sum[args, {a, 1, 3}, {b, 5, 7}]

现在简单:

Sum[a^2/b, iterators]

<块引用>

107/15

请参阅我对 保持函数范围作为变量的回答 Mathematica.SE 获取更多示例,因为这个问题密切相关.具体参见我的第二个答案中的 setSpec,它会自动创建 upvalue.

I need to evaluate a sum over Cartesian product of variable number of sets. Assuming f[...] is a multivariate function, define

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

But then

p[set[1, 2, 3], set[11, 12, 13]]

Gives the error: Sum::vloc: "The variable Sequence@@iterators cannot be localized so that it can be assigned to numerical values."

The following hack works:

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

Then

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

gives what I want:

f[1, 11] + f[1, 12] + f[2, 11] + f[2, 12] + f[3, 11] + f[3, 12]

I would like to know why the original does not.

As per belisarius there is much more elegant way to do this:

p[A__set] := Total[Outer[f, A],Length[{A}]];

解决方案

This has to do with evaluation order. Please see Tutorial: Evaluation as a reference.

Sum has the Attribute HoldAll:

Attributes[Sum]

{HoldAll, Protected, ReadProtected}

Because of this only arguments with certain heads such as Evaluate or Sequence or Symbols with upvalues will evaluate. You may think that your argument Sequence @@ iterators has the head Sequence, but it actually has the head Apply:

HoldForm @ FullForm[Sequence @@ iterators]

Apply[Sequence, iterators]

Sum expects literal arguments that match its declared syntax, and thus your code fails. You can force evaluation in several different ways. Arguably the most transparent is to add Evaluate:

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

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

107/15

More concisely you can leverage Function, SlotSequence, and Apply; evaluation takes place since neither Apply, nor Function by default, has HoldAll:

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

107/15

Both of these have a potential problem however: if a or b received a global value the Symbol in the definition of iterators will evaluate to this value causing another error:

a = 0;

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

Sum::itraw: Raw object 0 cannot be used as an iterator. >>

Instead you can store the iterator lists in a Hold expression and use the "injector pattern" to insert these values without complete evaluation:

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

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

107/15

Alternatively you could define iterators as an upvalue:

Sum[args___, iterators] ^:= Sum[args, {a, 1, 3}, {b, 5, 7}]

Now simply:

Sum[a^2/b, iterators]

107/15

Please see my answers to Keep function range as a variable on Mathematica.SE for more examples, as this question is closely related. Specifically see setSpec in my second answer which automates the upvalue creation.

这篇关于Wolfram Mathematica 中的 Sum[] 和 Sequence[]的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆