{-# LANGUAGE ImportQualifiedPost #-} import Data.AEq (AEq ((~==))) import Test.Hspec (context, describe, hspec, it, shouldBe) import Test.Hspec.QuickCheck (prop) import Test.QuickCheck (ioProperty, property, (==>)) import TestAdvanced qualified import TestDistribution qualified import TestEnumerator qualified import TestInference qualified import TestIntegrator qualified import TestPipes (hmms) import TestPipes qualified import TestPopulation qualified import TestSampler qualified import TestSequential qualified import TestStormerVerlet qualified import TestWeighted qualified main :: IO () main = hspec do describe "Stormer Verlet" $ it "conserves energy" $ do p1 <- TestStormerVerlet.passed1 p1 `shouldBe` True describe "Distribution" $ it "gives correct mean, variance and covariance" $ do p1 <- TestDistribution.passed1 p1 `shouldBe` True p2 <- TestDistribution.passed2 p2 `shouldBe` True p3 <- TestDistribution.passed3 p3 `shouldBe` True describe "Weighted" $ it "accumulates likelihood correctly" $ do passed <- TestWeighted.passed passed `shouldBe` True describe "Enumerator" do it "sorts samples and aggregates weights" $ TestEnumerator.passed2 `shouldBe` True it "gives correct answer for the sprinkler model" $ TestEnumerator.passed3 `shouldBe` True it "computes expectation correctly" $ TestEnumerator.passed4 `shouldBe` True describe "Integrator Expectation" do prop "expectation numerically" $ \mean var -> var > 0 ==> property $ TestIntegrator.normalExpectation mean (sqrt var) ~== mean describe "Integrator Variance" do prop "variance numerically" $ \mean var -> var > 0 ==> property $ TestIntegrator.normalVariance mean (sqrt var) ~== var describe "Sampler mean and variance" do it "gets right mean and variance" $ TestSampler.testMeanAndVariance `shouldBe` True describe "Integrator Volume" do prop "volume sums to 1" $ property $ \case [] -> True ls -> (TestIntegrator.volumeIsOne ls) describe "Integrator" do it "" $ all (== True) [ TestIntegrator.passed1, TestIntegrator.passed2, TestIntegrator.passed3, TestIntegrator.passed4, TestIntegrator.passed5, TestIntegrator.passed6, TestIntegrator.passed7, TestIntegrator.passed8, TestIntegrator.passed9, TestIntegrator.passed10, TestIntegrator.passed11, TestIntegrator.passed12, TestIntegrator.passed13, TestIntegrator.passed14 ] `shouldBe` True describe "Population" do context "controlling population" do it "preserves the population when not explicitly altered" do popSize <- TestPopulation.popSize popSize `shouldBe` 5 it "multiplies the number of samples when spawn invoked twice" do manySize <- TestPopulation.manySize manySize `shouldBe` 15 it "correctly computes population average" $ TestPopulation.popAvgCheck `shouldBe` True context "distribution-preserving transformations" do it "collapse preserves the distribution" do TestPopulation.transCheck1 `shouldBe` True TestPopulation.transCheck2 `shouldBe` True it "resample preserves the distribution" do TestPopulation.resampleCheck 1 `shouldBe` True TestPopulation.resampleCheck 2 `shouldBe` True describe "Sequential" do it "stops at every factor" do TestSequential.checkTwoSync 0 `shouldBe` True TestSequential.checkTwoSync 1 `shouldBe` True TestSequential.checkTwoSync 2 `shouldBe` True it "preserves the distribution" $ TestSequential.checkPreserve `shouldBe` True it "produces correct intermediate weights" do TestSequential.checkSync 0 `shouldBe` True TestSequential.checkSync 1 `shouldBe` True TestSequential.checkSync 2 `shouldBe` True describe "SMC" do it "terminates" $ seq TestInference.checkTerminateSMC () `shouldBe` () it "preserves the distribution on the sprinkler model" $ TestInference.checkPreserveSMC `shouldBe` True prop "number of particles is equal to its second parameter" $ \observations particles -> observations >= 0 && particles >= 1 ==> ioProperty do checkParticles <- TestInference.checkParticles observations particles return $ checkParticles == particles describe "SMC with systematic resampling" $ prop "number of particles is equal to its second parameter" $ \observations particles -> observations >= 0 && particles >= 1 ==> ioProperty do checkParticles <- TestInference.checkParticlesSystematic observations particles return $ checkParticles == particles describe "Equivalent Expectations" do prop "Gamma Normal" $ ioProperty . TestInference.testGammaNormal prop "Normal Normal" $ \n -> ioProperty (TestInference.testNormalNormal [max (-3) $ min 3 n]) prop "Beta Bernoulli" $ ioProperty . TestInference.testBetaBernoulli describe "Pipes: Urn" do it "Distributions are equivalent" do TestPipes.urns 10 `shouldBe` True describe "Pipes: HMM" do prop "pipe model is equivalent to standard model" $ \num -> property $ hmms $ take 5 num describe "SMC with stratified resampling" $ prop "number of particles is equal to its second parameter" $ \observations particles -> observations >= 0 && particles >= 1 ==> ioProperty do checkParticles <- TestInference.checkParticlesStratified observations particles return $ checkParticles == particles describe "Expectation from all inference methods" $ it "gives correct answer for the sprinkler model" do passed1 <- TestAdvanced.passed1 passed1 `shouldBe` True passed2 <- TestAdvanced.passed2 passed2 `shouldBe` True passed3 <- TestAdvanced.passed3 passed3 `shouldBe` True passed4 <- TestAdvanced.passed4 passed4 `shouldBe` True passed5 <- TestAdvanced.passed5 passed5 `shouldBe` True passed6 <- TestAdvanced.passed6 passed6 `shouldBe` True passed7 <- TestAdvanced.passed7 passed7 `shouldBe` True