在 Mathematica 中,如何为任意数量的参数编译函数 Outer[]?

发布于 2024-10-17 04:36:46 字数 1827 浏览 3 评论 0原文

如果我想从两个列表 list1list2 中查找所有可能的和,我可以使用 Outer[] 函数以及 规范Plus 作为组合运算符:

In[1]= list1 = {a, b};列表2 = {c, d}; Outer[Plus, list1, list2]

Out[1]= {{a + c, a + d}, {b + c, b + d}}

如果我想成为能够处理任意数量的列表,比如列表列表,

In[2]= listOfLists={list1, list2};

那么我知道如何找到所有可能的总和的唯一方法是使用Apply[] 函数(简写为 @@)以及 Join

In[3]=argumentsToPass=Join [{Plus},listOfLists]

Out[3]= {Plus, {a, b}, {c, d}}

In[4]= 外部@@ argumentToPass

Out[4]= {{a + c, a + d}, {b + c, b + d}}

或简单地

In[5]= 外部@@ Join[{Plus},listOfLists]

Out[5]= {{a + c, a + d}, {b + c, b + d}}

当我尝试编译:

In[6]= Compile[ ..... Outer @@ Join[{Plus},listOfLists] .... ]

Compile::cpapot: "编译函数参数 Outer 不支持 Outer@@Join[{Plus},listOfLists]] 唯一支持的函数参数是 Times、Plus 或 List。评估将使用未编译的函数。 “

问题是,我正在使用受支持的函数,即 Plus。问题似乎仅在于 Apply[] > 函数。因为如果我给它固定数量的列表到 external-plus 一起,它就可以正常工作

In[7]= Compile[{{bob, _Integer, 1}, {joe, _Integer, 1}}, Outer[Plus, bob, joe]]

Out[7]= CompiledFunction[{bob, joe}, Outer[Plus, bob, joe],-CompiledCode-]

但只要我使用 Apply,它破坏了

In[8]= Compile[{{bob, _Integer, 1}, {joe, _Integer, 1}}, Outer @@ Join[{Plus}, {bob, joe}]]

Out[8]= Compile::cpapot: "函数参数 Outer 不支持 Outer@@Join[{Plus},{bob,joe}] 的编译。唯一支持的函数参数是 Times、Plus 或 List。评估将使用未编译的函数。”

所以我的问题是:有没有办法避免这个错误,或者有没有办法计算从任意数字中提取的元素的所有可能总和编译函数中的列表?

(另外,我不确定“编译”是否是一个合适的标签。请告知。)

非常感谢。

If I want to find all possible sums from two lists list1 and list2, I use the Outer[] function with the specification of Plus as the combining operator:

In[1]= list1 = {a, b}; list2 = {c, d}; Outer[Plus, list1, list2]

Out[1]= {{a + c, a + d}, {b + c, b + d}}

If I want to be able to handle an arbitrary number of lists, say a list of lists,

In[2]= listOfLists={list1, list2};

then the only way I know how to find all possible sums is to use the Apply[] function (which has the short hand @@) along with Join:

In[3]= argumentsToPass=Join[{Plus},listOfLists]

Out[3]= {Plus, {a, b}, {c, d}}

In[4]= Outer @@ argumentsToPass

Out[4]= {{a + c, a + d}, {b + c, b + d}}

or simply

In[5]= Outer @@ Join[{Plus},listOfLists]

Out[5]= {{a + c, a + d}, {b + c, b + d}}

The problem comes when I try to compile:

In[6]= Compile[ ..... Outer @@ Join[{Plus},listOfLists] .... ]

Compile::cpapot: "Compilation of Outer@@Join[{Plus},listOfLists]] is not supported for the function argument Outer. The only function arguments supported are Times, Plus, or List. Evaluation will use the uncompiled function. "

The thing is, I am using a supported function, namely Plus. The problem seems to be solely with the Apply[] function. Because if I give it a fixed number of lists to outer-plus together, it works fine

In[7]= Compile[{{bob, _Integer, 1}, {joe, _Integer, 1}}, Outer[Plus, bob, joe]]

Out[7]= CompiledFunction[{bob, joe}, Outer[Plus, bob, joe],-CompiledCode-]

but as soon as I use Apply, it breaks

In[8]= Compile[{{bob, _Integer, 1}, {joe, _Integer, 1}}, Outer @@ Join[{Plus}, {bob, joe}]]

Out[8]= Compile::cpapot: "Compilation of Outer@@Join[{Plus},{bob,joe}] is not supported for the function argument Outer. The only function arguments supported are Times, Plus, or List. Evaluation will use the uncompiled function."

So my questions is: Is there a way to circumvent this error or, alternatively, a way to compute all possible sums of elements pulled from an arbitrary number of lists in a compiled function?

(Also, I'm not sure if "compilation" is an appropriate tag. Please advise.)

Thanks so much.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

萌化 2024-10-24 04:36:46

使用 With 的一种方法是,以编程方式创建编译函数:

Clear[makeCompiled];
makeCompiled[lnum_Integer] :=
 With[{listNames = Table[Unique["list"], {lnum}]},
   With[{compileArgs = {#, _Integer, 1} & /@ listNames},
      Compile @@ Join[Hold[compileArgs],
        Replace[Hold[Outer[Plus, listNames]], 
          Hold[Outer[Plus, {x__}]] :> Hold[Outer[Plus, x]], {0}]]]];

它可能可以做得更漂亮,但它确实有效。例如:

In[22]:= p2 = makeCompiled[2]
Out[22]= CompiledFunction[{list13,list14},Outer[Plus,list13,list14],-CompiledCode-]

In[23]:= p2[{1,2,3},{4,5}]
Out[23]= {{5,6},{6,7},{7,8}}

In[24]:= p3 = makeCompiled[3]
Out[24]= CompiledFunction[{list15,list16,list17},Outer[Plus,list15,list16,list17],-CompiledCode-]

In[25]:= p3[{1,2},{3,4},{5,6}]
Out[25]= {{{9,10},{10,11}},{{10,11},{11,12}}}

HTH

编辑:

您可以将已编译的函数隐藏在另一个函数后面,以便它是在运行时创建的,而您实际上看不到它:

In[33]:= 
Clear[computeSums]
computeSums[lists : {__?NumberQ} ..] := makeCompiled[Length[{lists}]][lists];

In[35]:= computeSums[{1, 2, 3}, {4, 5}]

Out[35]= {{5, 6}, {6, 7}, {7, 8}}

在这种情况下,您将面临编译的开销,因为您创建了一个已编译的函数每次都重新运行。您可以通过记忆化相当优雅地应对这种开销,使用 Module 变量进行持久化,以本地化您的记忆化定义:

In[44]:= 
Clear[computeSumsMemoized];
Module[{compiled},
  compiled[n_] := compiled[n] = makeCompiled[n];
  computeSumsMemoized[lists : {__?NumberQ} ..] := compiled[Length[{lists}]][lists]];

In[46]:= computeSumsMemoized[{1, 2, 3}, {4, 5}]

Out[46]= {{5, 6}, {6, 7}, {7, 8}}

One way it to use With, to create a compiled function programmatically:

Clear[makeCompiled];
makeCompiled[lnum_Integer] :=
 With[{listNames = Table[Unique["list"], {lnum}]},
   With[{compileArgs = {#, _Integer, 1} & /@ listNames},
      Compile @@ Join[Hold[compileArgs],
        Replace[Hold[Outer[Plus, listNames]], 
          Hold[Outer[Plus, {x__}]] :> Hold[Outer[Plus, x]], {0}]]]];

It can probably be done prettier, but it works. For example:

In[22]:= p2 = makeCompiled[2]
Out[22]= CompiledFunction[{list13,list14},Outer[Plus,list13,list14],-CompiledCode-]

In[23]:= p2[{1,2,3},{4,5}]
Out[23]= {{5,6},{6,7},{7,8}}

In[24]:= p3 = makeCompiled[3]
Out[24]= CompiledFunction[{list15,list16,list17},Outer[Plus,list15,list16,list17],-CompiledCode-]

In[25]:= p3[{1,2},{3,4},{5,6}]
Out[25]= {{{9,10},{10,11}},{{10,11},{11,12}}}

HTH

Edit:

You can hide the compiled function behind another one, so that it is created at run-time and you don't actually see it:

In[33]:= 
Clear[computeSums]
computeSums[lists : {__?NumberQ} ..] := makeCompiled[Length[{lists}]][lists];

In[35]:= computeSums[{1, 2, 3}, {4, 5}]

Out[35]= {{5, 6}, {6, 7}, {7, 8}}

You face an overhead of compiling in this case, since you create then a compiled function afresh every time. You can fight this overhead rather elegantly with memoization, using Module variables for persistence, to localize your memoized definitions:

In[44]:= 
Clear[computeSumsMemoized];
Module[{compiled},
  compiled[n_] := compiled[n] = makeCompiled[n];
  computeSumsMemoized[lists : {__?NumberQ} ..] := compiled[Length[{lists}]][lists]];

In[46]:= computeSumsMemoized[{1, 2, 3}, {4, 5}]

Out[46]= {{5, 6}, {6, 7}, {7, 8}}
鼻尖触碰 2024-10-24 04:36:46

这是我的第一篇文章。我希望我能做对。

如果您的输入是整数列表,我对编译此函数的价值持怀疑态度,至少在 Mathematica 7 中

是这样。例如:

f = Compile[{{a, _Integer, 1}, {b, _Integer, 1}, {c, _Integer, 1}, {d, _Integer, 1}, {e, _Integer, 1}}, 
        Outer[Plus, a, b, c, d, e]
    ];

a = RandomInteger[{1, 99}, #] & /@ {12, 32, 19, 17, 43};

Do[f @@ a, {50}] // Timing

Do[Outer[Plus, ##] & @@ a, {50}] // Timing

这两个 Timings 对我来说并没有显着不同,但这当然只是一个示例。重点是,与编译版本相比,Outer 已经相当快了。

如果除了编译速度之外还有其他原因,您可能会在 Tuples 而不是 Outer 中找到一些用处,但是您仍然受到需要张量输入的编译函数的限制。

f2 = Compile[{{array, _Integer, 2}}, 
      Plus @@@ Tuples@array
    ];

f2[{{1, 3, 7}, {13, 25, 41}}]

如果您的输入很大,那么可能需要采用不同的方法。给定一个整数列表,该函数将返回可能的总和以及获得每个总和的方法数量:

f3 = CoefficientRules@Product[Sum[x^i, {i, p}], {p, #}] &;

f3[{{1, 3, 7}, {13, 25, 41}}]

在许多情况下,这应该证明内存效率更高。

a2 = RandomInteger[{1, 999}, #] & /@ {50, 74, 55, 55, 90, 57, 47, 79, 87, 36};

f3[a2]; // Timing

MaxMemoryUsed[]

这花费了 3 秒和最少的内存,但尝试将 Outer 应用到 a2 会终止内核,并显示“没有更多可用内存”。

This is my first post. I hope I get this right.

If your inputs are lists of integers, I am skeptical of the value of compiling this function, at least in Mathematica 7.

For example:

f = Compile[{{a, _Integer, 1}, {b, _Integer, 1}, {c, _Integer, 1}, {d, _Integer, 1}, {e, _Integer, 1}}, 
        Outer[Plus, a, b, c, d, e]
    ];

a = RandomInteger[{1, 99}, #] & /@ {12, 32, 19, 17, 43};

Do[f @@ a, {50}] // Timing

Do[Outer[Plus, ##] & @@ a, {50}] // Timing

The two Timings are not significantly different for me, but of course this is only one sample. The point is merely that Outer is already fairly fast compared to the compiled version.

If you have reasons other than speed for compilation, you may find some use in Tuples instead of Outer, but you still have the constraint of compiled functions requiring tensor input.

f2 = Compile[{{array, _Integer, 2}}, 
      Plus @@@ Tuples@array
    ];

f2[{{1, 3, 7}, {13, 25, 41}}]

If your inputs are large, then a different approach may be in order. Given a list of lists of integers, this function will return the possible sums and the number of ways to get each sum:

f3 = CoefficientRules@Product[Sum[x^i, {i, p}], {p, #}] &;

f3[{{1, 3, 7}, {13, 25, 41}}]

This should prove to be far more memory efficient in many cases.

a2 = RandomInteger[{1, 999}, #] & /@ {50, 74, 55, 55, 90, 57, 47, 79, 87, 36};

f3[a2]; // Timing

MaxMemoryUsed[]

This took 3 seconds and minimal memory, but attempting the application of Outer to a2 terminated the kernel with "No more memory available."

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文