packages feed

moonlight-category-0.1.0.0: src-laws/Moonlight/Category/Effect/Laws/Generators.hs

{-# LANGUAGE DerivingStrategies #-}

module Moonlight.Category.Effect.Laws.Generators
  ( SampleFinObject (..),
    SampleFinMorphism (..),
    SampleComposableFinTriple (..),
    SampleOrdinalLower (..),
    SampleOrdinalUpper (..),
    SampleLowerObject (..),
    SampleUpperObject (..),
    SampleLowerMorphism (..),
    SampleUpperMorphism (..),
    SampleUnitObject (..),
    SampleUnitMorphism (..),
    SampleUnitTwoMorphism (..),
    allPairs,
    lawSuites,
  )
where

import Data.Kind (Type)
import Data.Function ((&))
import Data.Maybe (mapMaybe)
import qualified Hedgehog as HH
import qualified Hedgehog.Gen as Gen
import qualified Hedgehog.Range as Range
import Moonlight.Category.Effect.Fixture.FinCat (sampleFinCat)
import Moonlight.Category.Pure.FinCat
  ( FinMor,
    FinObj,
    allMorphisms,
    allObjects,
  )
import Moonlight.Category.Pure.Category (Category (..))
import Moonlight.Category.Pure.Poset
  ( LowerMor,
    OrdinalLower (..),
    OrdinalUpper (..),
    PosetOb (..),
    UpperMor,
    mkLowerMor,
    mkUpperMor,
  )
import Moonlight.Category.Pure.Unit
  ( UnitMor (..),
    UnitObj (..),
    UnitTwoMor (..),
  )
import Moonlight.Pale.Test.Laws.Suite (LawSuite, hedgehogLaw, lawGroup)
import qualified Test.Tasty.QuickCheck as QC

type SampleFinObject :: Type
newtype SampleFinObject = SampleFinObject {unSampleFinObject :: FinObj}
  deriving stock (Show)

type SampleFinMorphism :: Type
newtype SampleFinMorphism = SampleFinMorphism {unSampleFinMorphism :: FinMor}
  deriving stock (Show)

type SampleComposableFinTriple :: Type
data SampleComposableFinTriple = SampleComposableFinTriple FinMor FinMor FinMor
  deriving stock (Show)

type SampleOrdinalLower :: Type
newtype SampleOrdinalLower = SampleOrdinalLower {unSampleOrdinalLower :: OrdinalLower}
  deriving stock (Show)

type SampleOrdinalUpper :: Type
newtype SampleOrdinalUpper = SampleOrdinalUpper {unSampleOrdinalUpper :: OrdinalUpper}
  deriving stock (Show)

type SampleLowerObject :: Type
newtype SampleLowerObject = SampleLowerObject {unSampleLowerObject :: PosetOb OrdinalLower}
  deriving stock (Show)

type SampleUpperObject :: Type
newtype SampleUpperObject = SampleUpperObject {unSampleUpperObject :: PosetOb OrdinalUpper}
  deriving stock (Show)

type SampleLowerMorphism :: Type
newtype SampleLowerMorphism = SampleLowerMorphism {unSampleLowerMorphism :: LowerMor}
  deriving stock (Show)

type SampleUpperMorphism :: Type
newtype SampleUpperMorphism = SampleUpperMorphism {unSampleUpperMorphism :: UpperMor}
  deriving stock (Show)

type SampleUnitObject :: Type
newtype SampleUnitObject = SampleUnitObject {unSampleUnitObject :: UnitObj}
  deriving stock (Show)

type SampleUnitMorphism :: Type
newtype SampleUnitMorphism = SampleUnitMorphism {unSampleUnitMorphism :: UnitMor}
  deriving stock (Show)

type SampleUnitTwoMorphism :: Type
newtype SampleUnitTwoMorphism = SampleUnitTwoMorphism {unSampleUnitTwoMorphism :: UnitTwoMor}
  deriving stock (Show)

sampleObjects :: [FinObj]
sampleObjects = allObjects sampleFinCat

sampleMorphisms :: [FinMor]
sampleMorphisms = allMorphisms sampleFinCat

sampleComposableFinTriples :: [SampleComposableFinTriple]
sampleComposableFinTriples =
  sampleMorphisms
    >>= ( \firstMorphism ->
            sampleMorphisms
              >>= ( \secondMorphism ->
                      sampleMorphisms
                        & foldMap
                          ( \thirdMorphism ->
                              case
                                ( target sampleFinCat firstMorphism,
                                  source sampleFinCat secondMorphism,
                                  target sampleFinCat secondMorphism,
                                  source sampleFinCat thirdMorphism
                                )
                                of
                                  (Right firstTarget, Right secondSource, Right secondTarget, Right thirdSource)
                                    | firstTarget == secondSource && secondTarget == thirdSource ->
                                        [SampleComposableFinTriple firstMorphism secondMorphism thirdMorphism]
                                  _ -> []
                          )
                  )
        )

lowerMorphismSamples :: [LowerMor]
lowerMorphismSamples =
  [0 .. 32]
    >>= ( \lower ->
            mapMaybe (mkLowerMor (OrdinalLower lower) . OrdinalLower) [lower .. 32]
        )

upperMorphismSamples :: [UpperMor]
upperMorphismSamples =
  [0 .. 64]
    >>= ( \lower ->
            mapMaybe (mkUpperMor (OrdinalUpper lower) . OrdinalUpper) [lower .. 64]
        )

instance QC.Arbitrary SampleFinObject where
  arbitrary = SampleFinObject <$> QC.elements sampleObjects
  shrink _ = []

instance QC.Arbitrary SampleFinMorphism where
  arbitrary = SampleFinMorphism <$> QC.elements sampleMorphisms
  shrink _ = []

instance QC.Arbitrary SampleComposableFinTriple where
  arbitrary = QC.elements sampleComposableFinTriples
  shrink _ = []

instance QC.Arbitrary SampleOrdinalLower where
  arbitrary = SampleOrdinalLower . OrdinalLower <$> QC.chooseInt (0, 32)
  shrink (SampleOrdinalLower (OrdinalLower value)) =
    map (SampleOrdinalLower . OrdinalLower) (QC.shrink value)

instance QC.Arbitrary SampleOrdinalUpper where
  arbitrary = SampleOrdinalUpper . OrdinalUpper <$> QC.chooseInt (0, 64)
  shrink (SampleOrdinalUpper (OrdinalUpper value)) =
    map (SampleOrdinalUpper . OrdinalUpper) (QC.shrink value)

instance QC.Arbitrary SampleLowerObject where
  arbitrary = SampleLowerObject . PosetOb . OrdinalLower <$> QC.chooseInt (0, 32)
  shrink (SampleLowerObject (PosetOb (OrdinalLower value))) =
    map (SampleLowerObject . PosetOb . OrdinalLower) (QC.shrink value)

instance QC.Arbitrary SampleUpperObject where
  arbitrary = SampleUpperObject . PosetOb . OrdinalUpper <$> QC.chooseInt (0, 64)
  shrink (SampleUpperObject (PosetOb (OrdinalUpper value))) =
    map (SampleUpperObject . PosetOb . OrdinalUpper) (QC.shrink value)

instance QC.Arbitrary SampleLowerMorphism where
  arbitrary = SampleLowerMorphism <$> QC.elements lowerMorphismSamples
  shrink _ = []

instance QC.Arbitrary SampleUpperMorphism where
  arbitrary = SampleUpperMorphism <$> QC.elements upperMorphismSamples
  shrink _ = []

instance QC.Arbitrary SampleUnitObject where
  arbitrary = pure (SampleUnitObject UnitObj)
  shrink _ = []

instance QC.Arbitrary SampleUnitMorphism where
  arbitrary = pure (SampleUnitMorphism UnitMor)
  shrink _ = []

instance QC.Arbitrary SampleUnitTwoMorphism where
  arbitrary = pure (SampleUnitTwoMorphism (UnitTwoMor UnitMor UnitMor))
  shrink _ = []

hedgehogSampleFinObject :: HH.Gen FinObj
hedgehogSampleFinObject = Gen.element sampleObjects

hedgehogSampleFinMorphism :: HH.Gen FinMor
hedgehogSampleFinMorphism = Gen.element sampleMorphisms

finObjectGeneratorSound :: FinObj -> Bool
finObjectGeneratorSound objectValue = objectValue `elem` sampleObjects

finMorphismGeneratorSound :: FinMor -> Bool
finMorphismGeneratorSound morphism = morphism `elem` sampleMorphisms

allPairs :: [a] -> [(a, a)]
allPairs values =
  values >>= (\leftValue -> fmap (\rightValue -> (leftValue, rightValue)) values)

lawSuites :: [LawSuite]
lawSuites =
  [ lawGroup
      "generators"
      [ hedgehogLaw "generator_fin_object_sound" hedgehogSampleFinObject finObjectGeneratorSound,
        hedgehogLaw "generator_fin_morphism_sound" hedgehogSampleFinMorphism finMorphismGeneratorSound,
        hedgehogLaw
          "generator_ordinal_lower_bounds"
          (OrdinalLower <$> Gen.int (Range.linear 0 32))
          (\(OrdinalLower value) -> value >= 0 && value <= 32),
        hedgehogLaw
          "generator_ordinal_upper_bounds"
          (OrdinalUpper <$> Gen.int (Range.linear 0 64))
          (\(OrdinalUpper value) -> value >= 0 && value <= 64)
      ]
  ]