我最近询问为什么PatternTest
引起了大量不必要的评估:PatternTest not optimized? Leonid回答说,对我来说这是一个相当可疑的方法是必要的。我可以接受,虽然我更喜欢更有效的替代方案。
我现在意识到,我相信Leonid已经说过一段时间了,这个问题在 Mathematica 中运行得更深,我感到很困扰。我无法理解为什么这不是或不能更好地优化。
考虑这个例子:
list = RandomReal[9, 20000];
Head /@ list; // Timing
MatchQ[list, {x__Integer, y__}] // Timing
{0., Null}
{1.014, False}
检查列表的头部基本上是即时的,但检查模式需要一秒钟。当然 Mathematica 可以识别出由于列表的第一个元素不是整数,因此模式不能匹配,与PatternTest
的情况不同,我无法看到模式中是否存在任何可变性。对此有何解释?
答案 0 :(得分:8)
MatchQ
解压缩这些类型的测试。原因是没有实施任何特殊情况。原则上它可以包含任何内容。
On["Packing"]
MatchQ[list, {x_Integer, y__}] // Timing
MatchQ[list, {x__Integer, y__}] // Timing
改善这一点非常棘手 - 如果你打破模式匹配器就会遇到严重的问题。
编辑1:
确实,解包不是O(n ^ 2)复杂性的原因。但是,它确实表明,对于MatchQ[list, {x__Integer, y__}]
部分,代码转到算法的另一部分(需要解压缩列表)。还有一些需要注意的事项:只有当两个模式都是__
时才会出现这种复杂性,如果其中任何一个都是_
算法具有更好的复杂性。
然后算法会经历所有n * n个潜在的匹配,似乎没有提前救助。大概是因为可能需要构建其他需要这种复杂性的模式 - 问题是上述模式迫使匹配器采用非常通用的算法。
然后我希望MatchQ[list, {Shortest[x__Integer], __}]
和朋友,但无济于事。
所以,我的两分钱:要么使用不同的模式(并打开["包装"]以查看它是否转到一般匹配器)或进行预检DeveloperPackedArrayQ[expr] && Head[expr[[1]]]===Integer
或一些这样的。
答案 1 :(得分:1)
@the author of the first answer
。据我所知,反向生成和读取可用信息,可能是由于检查模式的方式不同。事实上 - 正如他们所说 - 一个特殊的哈希码用于模式匹配。这个散列(基本上是FNV-1循环)使得检查与所涉及的表达类型相关的特定模式(几个xor操作的问题)非常容易。散列算法在表达式内循环,每个子部分与前一个子部分的输出进行xorred。特殊的xor值用于每个原子表达式 - machineInts,machineReals,bigNums,Rationals等。因此,例如,_Integer
很容易检查,因为任何整数的散列都是由整数的xor值组成的,所以我们需要做的就是进行逆运算并查看是否匹配 - 即如果我们得到一些特定的价值或类似的东西(对不起,如果我对实际的实施细节含糊不清。它的WIP)。对于一般或不常见的模式,检查可能无法利用此哈希值并需要不同的东西。
@the OP
Head[]
只是对内部表达式起作用,取表达式的第一个指针的值(表达式实现为指针数组)。这样做就像复制和打印字符串一样简单 - 非常快。在这种情况下甚至不调用模式匹配引擎。