packages feed

moonlight-algebra-0.1.0.0: src-laws/Moonlight/Algebra/Test/Generators.hs

{-# LANGUAGE DerivingStrategies #-}

module Moonlight.Algebra.Test.Generators
  ( AlgebraGeneratorConfig (..),
    defaultAlgebraGeneratorConfig,
    genBatch,
    genFreeAbelianGroup,
    genIntBasis,
    genIntegerCoefficient,
    genIntegerLawValue,
    genIntegerWeight,
    genLaneVector,
    genModulus,
    genOrientation,
    genPolynomial,
    genPowerSet,
    genSparseVec,
    genZn,
  )
where

import GHC.TypeNats (KnownNat, type (<=))
import Data.Vector.Unboxed qualified as UVector
import qualified Hedgehog as HH
import qualified Hedgehog.Gen as Gen
import qualified Hedgehog.Range as Range
import Moonlight.Algebra

data AlgebraGeneratorConfig = AlgebraGeneratorConfig
  { collectionLengthRange :: Range.Range Int,
    integerLawRange :: Range.Range Integer,
    integerCoefficientRange :: Range.Range Integer,
    integerWeightRange :: Range.Range Integer,
    intBasisRange :: Range.Range Int,
    modulusRange :: Range.Range Integer,
    znRepresentativeRange :: Range.Range Integer
  }

defaultAlgebraGeneratorConfig :: AlgebraGeneratorConfig
defaultAlgebraGeneratorConfig =
  AlgebraGeneratorConfig
    { collectionLengthRange = Range.linear 0 16,
      integerLawRange = Range.linear (-1000) 1000,
      integerCoefficientRange = Range.linear (-100) 100,
      integerWeightRange = Range.linear (-20) 20,
      intBasisRange = Range.linear (-8) 8,
      modulusRange = Range.linear 2 100,
      znRepresentativeRange = Range.linear (-1000) 1000
    }

genBatch :: AlgebraGeneratorConfig -> HH.Gen a -> HH.Gen (Batch a)
genBatch config genElement =
  Batch <$> Gen.list (collectionLengthRange config) genElement

genFreeAbelianGroup :: Ord g => AlgebraGeneratorConfig -> HH.Gen g -> HH.Gen (FreeAbelianGroup g)
genFreeAbelianGroup config genGenerator =
  fromTerms <$> Gen.list (collectionLengthRange config) ((,) <$> genGenerator <*> genIntegerWeight config)

genIntBasis :: AlgebraGeneratorConfig -> HH.Gen Int
genIntBasis =
  Gen.int . intBasisRange

genIntegerCoefficient :: AlgebraGeneratorConfig -> HH.Gen Integer
genIntegerCoefficient =
  Gen.integral . integerCoefficientRange

genIntegerLawValue :: AlgebraGeneratorConfig -> HH.Gen Integer
genIntegerLawValue =
  Gen.integral . integerLawRange

genIntegerWeight :: AlgebraGeneratorConfig -> HH.Gen Integer
genIntegerWeight =
  Gen.integral . integerWeightRange

genLaneVector :: HH.Gen LaneVector
genLaneVector =
  laneVectorFromLanes . UVector.fromList
    <$> Gen.list
      (Range.constant laneCount laneCount)
      (Gen.word64 Range.linearBounded)

genModulus :: AlgebraGeneratorConfig -> HH.Gen Integer
genModulus =
  Gen.integral . modulusRange

genOrientation :: HH.Gen Orientation
genOrientation =
  Gen.element [Positive, Negative]

genPolynomial :: (Eq r, AdditiveGroup r) => AlgebraGeneratorConfig -> HH.Gen r -> HH.Gen (Polynomial r)
genPolynomial config genScalar =
  fromCoefficients <$> Gen.list (collectionLengthRange config) genScalar

genPowerSet :: Ord a => AlgebraGeneratorConfig -> HH.Gen a -> HH.Gen (PowerSet a)
genPowerSet config genElement =
  fromList <$> Gen.list (collectionLengthRange config) genElement

genSparseVec ::
  (Eq r, AdditiveGroup r, Ord g) =>
  AlgebraGeneratorConfig ->
  HH.Gen g ->
  HH.Gen r ->
  HH.Gen (SparseVec r g)
genSparseVec config genGenerator genScalar =
  fromEntries <$> Gen.list (collectionLengthRange config) ((,) <$> genGenerator <*> genScalar)

genZn :: forall n. (KnownNat n, 1 <= n) => AlgebraGeneratorConfig -> HH.Gen (Zn n)
genZn config =
  mkZn <$> Gen.integral (znRepresentativeRange config)