我刚刚看过a video,它为基于性能的测试提供了集成收缩的概念。该方法似乎比类型定向收缩具有一些优势,但是在this reddit thread中指出,集成收缩方法不适用于单子发电机:
以这种方式收缩并不适合发电机的单调风格。这是一个示例,请考虑生成一个任意列表(暂时忽略终止):
do x <- arbitrary xs <- arbitrary return (x:xs)
现在,收缩的默认行为是先收缩x(使xs保持恒定),然后收缩xs(使xs保持恒定),这严重地限制了收缩(局部最小值的概念现在变得不那么牢固了)。
我将以上评论视为“综合收缩可能无法提供全局最小反例”。但是,由于hedgehog
似乎能够为列表中的失败属性找到最少的计数器示例,所以我想知道是否有一个示例可以显示上面引用中指出的缺点。
答案 0 :(得分:2)
用微积分的术语来说,问题在于您没有遵循负梯度(最陡下降),而是先沿1个轴最小化,然后沿另一个轴最小化。根据这种类比,很容易提出至少一个人为的例子-考虑函数
-- f x y = ((x^2 - 1)^2 - 0.2*x) * ((y^2 - 1/2)^2 - 0.1*y)
f x y = (x^4 - 2.2*x^2 + 1) * (y^4 - 1.1*y^2 + 1/4)
,我们正在对其属性f x y > 0
进行测试,可以说一个最小的示例将具有一个最接近原点(0, 0)
的点。根据首先开始收缩的位置,完全有可能最终接近(±1, 0)
,因为先调整x
,然后再不允许y
进行太多更改。但是,在理想情况下,您可能希望以接近(0, ±1/2)
的某个位置来满足最小值标准。
答案 1 :(得分:0)
仅供参考,这是一个涉及列表的示例:
{-# LANGUAGE OverloadedStrings #-}
module Main where
import Hedgehog
import qualified Hedgehog.Gen as Gen
import qualified Hedgehog.Range as Range
notLargeOrBothNotEmpty :: Property
notLargeOrBothNotEmpty = property $ do
xs <- forAll randomIntLists
ys <- forAll randomIntLists
assert $ length xs < 4 && (xs /= [] && ys /=[])
where
randomIntLists = Gen.frequency
[ (1, Gen.list (Range.constant 0 1) randomInt)
, (10, Gen.list (Range.constant 1 100) randomInt)
]
randomInt = Gen.integral (Range.constat 1 10)
main :: IO Bool
main = checkParallel $
Group "Test.Example" [("Produce a minimal counter-example", notLargeOrBothNotEmpty)]
因此刺猬有时会返回列表( [ 1 , 1 , 1 , 1 ], [])
作为反例。但是,([], [])
是一个较小的反例(hedgehog
有时也会报告)。

在这种情况下,违反该属性的条件是:
4 <= length xs || (xs == [] && ys == [])
如果最初发现一个反例,其中ys /= []
和4 <= length xs
,则集成收缩方法将首先尝试收缩xs
,然后将继续收缩ys
并保持{ {1}}常量,正如我在原始问题中引用的帖子中所述。