显示整合收缩的局限性的示例

时间:2019-01-28 23:53:09

标签: haskell quickcheck property-based-testing haskell-hedgehog

我刚刚看过a video,它为基于性能的测试提供了集成收缩的概念。该方法似乎比类型定向收缩具有一些优势,但是在this reddit thread中指出,集成收缩方法不适用于单子发电机:

  

以这种方式收缩并不适合发电机的单调风格。这是一个示例,请考虑生成一个任意列表(暂时忽略终止):

do x <- arbitrary
   xs <- arbitrary
   return (x:xs)
     

现在,收缩的默认行为是先收缩x(使xs保持恒定),然后收缩xs(使xs保持恒定),这严重地限制了收缩(局部最小值的概念现在变得不那么牢固了)。

我将以上评论视为“综合收缩可能无法提供全局最小反例”。但是,由于hedgehog似乎能够为列表中的失败属性找到最少的计数器示例,所以我想知道是否有一个示例可以显示上面引用中指出的缺点。

2 个答案:

答案 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)

See plot on WolframAlpha

,我们正在对其属性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}}常量,正如我在原始问题中引用的帖子中所述。