3

我正在 Haskell 中创建一个 Matrix 模块,我想使用 QuickCheck 来测试我的代码的一些属性。具体来说,我想生成具有关联逆的随机矩阵。以下是我尝试创建生成此类矩阵的 QuickCheck 生成器。

invertibleMatrix :: (Num a, Arbitrary a) => Gen (Matrix a)
invertibleMatrix = do s <- choose (2,10)
                      a <- vectorOf s (vector s)
                      if (det (Matrix a) == 0) then
                        invertibleMatrix
                      else
                        return (Matrix a)

该代码首先创建一个介于 2 到 10 之间的大小,然后创建一个由该大小的向量组成的向量。如果行列式为零,则矩阵不可逆,因此我递归调用 invertibleMatrix。否则我返回新矩阵。

问题是,当我把它放在一个属性中进行测试时,这段代码并没有终止。(我认为它不断创建相同的 sxs 零元素矩阵,显然没有逆矩阵,因此它进入了无限循环)。我究竟做错了什么?我该如何解决?谢谢。

标记

4

3 回答 3

2

作为绕过您的问题的一种方式,您可能会注意到,如果A是一个n×n矩阵,则A - tI对于除t的最多n 个值(即A的特征值)之外的所有值都是可逆的。因此,生成一个矩阵,如果它不可逆,则向它添加一个小的整数倍数,并继续尝试直到它是。然后该过程保证终止(只要底层数字类型表现得相当好,浮点有时不会,例如,如果A的条目远大于您尝试的t的值)。

于 2012-04-27T11:25:37.617 回答
1
squareMatrix :: (Num a, Arbitrary a) => Gen (Matrix a)
squareMatrix = do s <- choose (2,6)
                  a <- vectorOf s (vector s)
                  return (Matrix a)

invertibleMatrix :: (Num a, Arbitrary a) => Gen (Matrix a)
invertibleMatrix = suchThat squareMatrix ((/=0) . det) 

如果有人想知道,这就是解决方案。

标记

于 2012-04-28T09:38:31.567 回答
0

我没有对此进行测试,但我认为你想要的那种扰动可以从通常用于实现随机函数的 CoArbitrary 中获取。

invertibleMatrix :: (Num a, Arbitrary a) => Gen (Matrix a)
invertibleMatrix = kick seed where
  seed :: Integer
  seed = 0
  kick n = do
    s <- choose (2,10)
    a <- vectorOf s (vector s)
    if (det (Matrix a) == 0) then
      coarbitrary (kick (succ n))
    else
      return (Matrix a)
于 2012-04-27T06:25:20.573 回答