Added a QuickCheck test for the equality-solving part of the Omega test

This commit is contained in:
Neil Brown 2007-12-13 15:33:14 +00:00
parent b1a8f1d30d
commit cbeb3ecd95

View File

@ -25,6 +25,7 @@ import qualified Data.Map as Map
import qualified Data.Set as Set import qualified Data.Set as Set
import Prelude hiding (fail) import Prelude hiding (fail)
import Test.HUnit import Test.HUnit
import Test.QuickCheck
import ArrayUsageCheck import ArrayUsageCheck
@ -338,6 +339,72 @@ testArrayCheck = TestList
arrayise :: [Integer] -> Array Int Integer arrayise :: [Integer] -> Array Int Integer
arrayise = simpleArray . zip [0..] arrayise = simpleArray . zip [0..]
-- QuickCheck tests for Omega Test:
-- The idea is to begin with a random list of integers, representing transformed y_i variables.
-- This will be the solution. Feed this into a random list of inequalities. The inequalities do
-- not have to be true; they merely have to exist. Then slowly transform
--TODO generate negative coeffs, and allow zero coefficients (but be careful we don't
-- produce unsolveable equations, e.g. where one is all zeroes, or a_3 is zero in all of them)
-- | Generates a list of random numbers of the given size, where the numbers are all co-prime.
-- This is so they can be used as normalised coefficients in a linear equation
coprimeList :: Int -> Gen [Integer]
coprimeList size = do non_normal <- replicateM size $ choose (1,100)
return $ map (\x -> x `div` (foldl mygcd 0 non_normal)) non_normal
-- | Generates a list of lists of co-prime numbers, where each list is distinct.
-- The returned list of lists will be square; N equations, each with N items
distinctCoprimeLists :: Int -> Gen [[Integer]]
distinctCoprimeLists size = distinctCoprimeLists' [] size
where
-- n is the number left to generate; size is still the "width" of the lists
distinctCoprimeLists' :: [[Integer]] -> Int -> Gen [[Integer]]
distinctCoprimeLists' result 0 = return result
distinctCoprimeLists' soFar n = do next <- coprimeList size
if (next `elem` soFar)
then distinctCoprimeLists' soFar n -- Try again
else distinctCoprimeLists' (soFar ++ [next]) (n - 1)
-- | Given a solution, and the coefficients, work out the result.
-- Effectively the dot-product of the two lists.
calcUnits :: [Integer] -> [Integer] -> Integer
calcUnits a b = foldl (+) 0 $ zipWith (*) a b
-- | Given the solution for an equation (values of x_1 .. x_n), generates
-- equalities and inequalities. The equalities will all be true and consistent,
-- the inequalities will all turn out to be equal. That is, when the inequalities
-- are resolved, the LHS will equal 0. Therefore we can generate the inequalities
-- using the same method as equalities. Also, the equalities are assured to be
-- distinct. If they were not distinct (one could be transformed into another by scaling)
-- then the equation set would be unsolveable.
generateEqualities :: [Integer] -> Gen (EqualityProblem, InequalityProblem)
generateEqualities solution = do eqCoeffs <- distinctCoprimeLists num_vars
ineqCoeffs <- distinctCoprimeLists num_vars
return (map mkCoeffArray eqCoeffs, map mkCoeffArray ineqCoeffs)
where
num_vars = length solution
mkCoeffArray coeffs = arrayise $ (negate $ calcUnits solution coeffs) : coeffs
newtype OmegaTestInput = OMI (EqualityProblem, InequalityProblem) deriving (Show)
-- | Generates an Omega test problem with between 1 and 10 variables (incl), where the solutions
-- are numbers between -20 and + 20 (incl).
generateProblem :: Gen OmegaTestInput
generateProblem = (choose (1,10) >>= (\n -> replicateM n $ choose (-20,20)) >>= generateEqualities) >>* OMI
instance Arbitrary OmegaTestInput where
arbitrary = generateProblem
qcOmegaEquality :: Test
qcOmegaEquality = TestCase $ check (defaultConfig { configMaxTest = 1000}) prop
where
prop (OMI (eq,ineq)) = omegaCheck actAnswer
where
actAnswer = solveConstraints eq ineq
omegaCheck (Just ineqs) = all (all (== 0) . elems) ineqs
omegaCheck Nothing = False
tests :: Test tests :: Test
tests = TestList tests = TestList
@ -347,6 +414,7 @@ tests = TestList
-- ,testParUsageCheck -- ,testParUsageCheck
,testReachDef ,testReachDef
,testArrayCheck ,testArrayCheck
,qcOmegaEquality
] ]