gpt4 book ai didi

wolfram-mathematica - 非标准评估和PackedArray

转载 作者:行者123 更新时间:2023-12-04 18:15:07 27 4
gpt4 key购买 nike

我之前有asked如何制作allTrue[{x,list},test]函数,该函数可保护占位符x免受当前上下文中的求值,就像Table[expr,{x,...}]保护x一样

我最终使用的配方间歇性地失败了,我发现问题归结于将列表自动转换为PackedArrays。这是一个失败的例子

SetAttributes[allTrue, HoldAll];
allTrue[{var_, lis_}, expr_] :=
LengthWhile[lis,
TrueQ[ReleaseHold[Hold[expr] /. HoldPattern[var] -> #]] &] ==
Length[lis];
allTrue[{y, Developer`ToPackedArray[{1, 1, 1}]}, y > 0]

无论是否将 allTrue[{x,{1,2,3}},x>0]自动转换为 True,我都希望 {1,2,3}返回 PackedArray,实现它的更好方法是什么?

最佳答案

这是我已经使用了一段时间的版本(最初将其写成我的书的第二版,但最终使用了很多)。如果参数表示一些未评估的代码,则如果我们希望将代表一个特定子句的单个代码以未评估的形式传递给它,则测试函数必须具有HoldAllHoldFirst属性。

ClearAll[fastOr];
Attributes[fastOr] = {HoldRest};
fastOr[test_, {args___}] := fastOr[test, args];
fastOr[test_, args___] :=
TrueQ[Scan[
Function[arg, If[test[arg], Return[True]], HoldAll],
Hold[args]]];

编辑:我刚刚注意到,问题所在页面底部的Daniel Reeves解决方案与该解决方案非常相似。主要区别在于,我既关心短路问题,又保持论据不被评估(请参阅下文),而Daniel则只关注短路问题。

它确实具有短路行为。我们需要 HoldRest属性,因为我们希望将参数保留为未评估的形式。我们还需要纯函数中的 HoldAll(或 HoldFirst)属性,以保留未评估的每个参数,直到将其传递给 test为止。现在是否在 test主体中使用它之前是否对其进行评估取决于 test的属性。举个例子:
Clear[fullSquareQ];
fullSquareQ[x_Integer] := IntegerQ[Sqrt[x]];

In[13]:= Or @@ Map[fullSquareQ, Range[50000]] // Timing

Out[13]= {0.594, True}

In[14]:= fastOr[fullSquareQ, Evaluate[Range[10000]]] // Timing

Out[14]= {0., True}

这是一个示例,其中我们传递了一些引起副作用(打印)的代码作为参数。最后一个参数的代码没有机会执行,因为已经在上一个子句中确定了结果:
In[15]:= fastOr[# &, Print["*"]; False, Print["**"]; False, 
Print["***"]; True, Print["****"]; False]

During evaluation of In[15]:= *

During evaluation of In[15]:= **

During evaluation of In[15]:= ***

Out[15]= True

请注意,由于 fastOr接受通用的未评估代码段作为 Or的子句,因此,如果您不关心值的开头是否要被评估(如 Evaluate的情况),则必须将值列表包装在 Range中。上面的示例)。

最后,我将说明 fastOr的保留代码的程序化构造,以显示其用法(如果需要,可以考虑使用保留表达式进行速成教程)。使用保留表达式时,以下函数非常有用:
joinHeld[a___Hold] := Hold @@ Replace[Hold[a], Hold[x___] :> Sequence[x], {1}];

例子:
In[26]:= joinHeld[Hold[Print[1]], Hold[Print[2], Print[3]], Hold[], Hold[Print[4]]]

Out[26]= Hold[Print[1], Print[2], Print[3], Print[4]]

这是我们使用它来以编程方式构造在上面的Print-s示例中使用的保留参数的方式:
In[27]:= 
held = joinHeld @@ MapThread[Hold[Print[#]; #2] &,
{NestList[# <> "*" &, "*", 3], {False, False, True, False}}]

Out[27]= Hold[Print["*"]; False, Print["**"]; False, Print["***"]; True, Print["****"]; False]

要将其传递给 fastOr,我们将使用另一个有用的习惯用法:在 Hold[args]之前附加(或添加),直到获得所有函数参数,然后再使用 Apply(请注意,通常,如果我们不希望在该部分添加/在进行评估之前,我们必须将其包装在 Unevaluated中,因此常规用法看起来像 Append[Hold[parts___],Unevaluated[newpart]]):
In[28]:= fastOr @@ Prepend[held, # &]

During evaluation of In[28]:= *

During evaluation of In[28]:= **

During evaluation of In[28]:= ***

Out[28]= True

关于您所指的原始实现,您可以看一下我对它的评论。问题在于TakeWhile和LengthWhile在8.0.0版中存在打包数组的错误,它们在8.0.1的源中已修复-因此,从8.0.1开始,您可以使用我的版本或Michael的版本。

高温超导

编辑:

我只是注意到在您提到的帖子中,您想要一个不同的语法。尽管在这种情况下采用 fastOr采取的方法不是很困难,但这是一种不同的实现,可以说与该特定语法的现有语言结构更紧密地对应。我建议使用 Table和异常,因为 Table中的迭代器接受所需的相同语法。这里是:
ClearAll[AnyTrue, AllTrue];
SetAttributes[{AnyTrue, AllTrue}, HoldAll];
Module[{exany, exall},
AnyTrue[iter : {var_Symbol, lis_List}, expr_] :=
TrueQ[Catch[Table[If[TrueQ[expr], Throw[True, exany]], iter], exany]];
AllTrue[iter : {var_Symbol, lis_List}, expr_] :=
Catch[Table[If[! TrueQ[expr], Throw[False, exall]], iter], exall] =!= False;
];

几句话解释:我在顶层使用Module,因为我们只需要定义一次的自定义异常标记,也可以在定义时做到这一点。打破Table的方法是通过异常。效果不是很好,并且对性能的影响不大,但是我们购买了由 Table完成的迭代器变量的自动动态本地化和简单性。为了安全地做到这一点,我们必须使用唯一的标签来标记一个异常,这样我们就不会错误地捕获其他异常。我发现使用Module创建持久性异常标记通常是一个非常有用的技巧。现在,举一些例子:
In[40]:= i = 1

Out[40]= 1

In[41]:= AnyTrue[{i, {1, 2, 3, 4, 5}}, i > 3]

Out[41]= True

In[42]:= AnyTrue[{i, {1, 2, 3, 4, 5}}, i > 6]

Out[42]= False

In[43]:= AllTrue[{i, {1, 2, 3, 4, 5}}, i > 3]

Out[43]= False

In[44]:= AllTrue[{i, {1, 2, 3, 4, 5}}, i < 6]

Out[44]= True

In[45]:= AllTrue[{a, {1, 3, 5}}, AnyTrue[{b, {2, 4, 5}}, EvenQ[a + b]]]

Out[45]= True

In[46]:= AnyTrue[{a, {1, 3, 5}}, AllTrue[{b, {2, 4, 5}}, EvenQ[a + b]]]

Out[46]= False

我从对 i的赋值开始,以表明迭代器变量的可能全局值无关紧要- Table负责处理。最后,请注意(正如我在其他地方评论的那样),您对 AllTrueAnyTrue的原始签名过于严格,在某种意义上说,以下内容不起作用:
In[47]:= lst = Range[5];
AllTrue[{i, lst}, i > 3]

Out[48]= AllTrue[{i, lst}, i > 3]

(由于 lst属性,由于 HoldAll表示列表的事实在模式匹配时未知)。没有充分的理由保持这种行为,因此您只需删除 _List检查: AnyTrue[iter : {var_Symbol, lis_}, expr_],以及类似的 AllTrue,将涵盖此类用例。

关于wolfram-mathematica - 非标准评估和PackedArray,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4911827/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com