packages feed

pure-noise-0.2.1.1: src/Numeric/Noise/Internal/Math.hs

{-# LANGUAGE OverloadedLists #-}

-- |
-- Maintainer: Jeremy Nuttall <jeremy@jeremy-nuttall.com>
-- License: BSD-3-Clause
-- Stability : experimental
module Numeric.Noise.Internal.Math (
  Seed,
  Hash,
  lerp,
  cubicInterp,
  hermiteInterp,
  quinticInterp,
  clamp,
  primeX,
  primeY,
  primeZ,
  hash2,
  hash3,
  infinity,
  g2,
  sqrt3,
  valCoord2,
  valCoord3,
  gradCoord2,
  gradCoord3,
  maxHash,
) where

import Data.Bits
import Data.Int
import Data.Primitive.PrimArray
import Data.Word

-- | Seed value for deterministic noise generation.
--
-- Using the same 'Seed' value will produce the same noise pattern,
-- allowing for reproducible results. Different seed values produce
-- different, independent noise patterns.
type Seed = Word64

-- | Internal hash value type used in noise calculations.
type Hash = Int32

-- | Linear interpolation between two values.
--
-- Monotonic lerp
lerp
  :: (Num a)
  => a
  -- ^ start
  -> a
  -- ^ end
  -> a
  -- ^ parameter in range [0, 1]
  -> a
lerp v0 v1 t = v0 + t * (v1 - v0)
{-# INLINE [1] lerp #-}

{-# RULES
"lerp/Float/0" forall (a :: Float) b.
  lerp a b 0 =
    a
"lerp/Double/0" forall (a :: Double) b.
  lerp a b 0 =
    a
"lerp/Float/1" forall (a :: Float) b.
  lerp a b 1 =
    b
"lerp/Double/1" forall (a :: Double) b.
  lerp a b 1 =
    b
"lerp/id" forall a t. lerp a a t = a
"lerp/compose/start" forall a b t u.
  lerp (lerp a b u) b t =
    lerp a b (u + t - t * u)
"lerp/compose/end" forall a b t u.
  lerp a (lerp a b u) t =
    lerp a b (t * u)
  #-}

-- | cubic interpolation
cubicInterp :: (Num a) => a -> a -> a -> a -> a -> a
cubicInterp a !b c d !t =
  let !c' = c - a
      !a' = a - b
      !p = (d - c) - a'
      !b' = a' - p
   in b + t * (c' + t * (b' + t * p))
{-# INLINE [1] cubicInterp #-}

{-# RULES
"cubicInterp/Float/0" forall (a :: Float) b c d.
  cubicInterp a b c d 0 =
    b
"cubicInterp/Double/0" forall (a :: Double) b c d.
  cubicInterp a b c d 0 =
    b
"cubicInterp/Float/1" forall (a :: Float) b c d.
  cubicInterp a b c d 1 =
    c
"cubicInterp/Double/1" forall (a :: Double) b c d.
  cubicInterp a b c d 1 =
    c
"cubicInterp/Float/0.5" forall (a :: Float) b c d.
  cubicInterp a b c d (0.5 :: Float) =
    0.125 * (-a + 5 * b + 5 * c - d)
"cubicInterp/Double/0.5" forall (a :: Double) b c d.
  cubicInterp a b c d (0.5 :: Double) =
    0.125 * (-a + 5 * b + 5 * c - d)
  #-}

-- | hermite interpolation
hermiteInterp :: (Num a) => a -> a
hermiteInterp t = t * t * (3 - 2 * t)
{-# INLINE [1] hermiteInterp #-}

{-# RULES
"hermiteInterp/Float/0" hermiteInterp (0 :: Float) = 0
"hermiteInterp/Double/0" hermiteInterp (0 :: Double) = 0
"hermiteInterp/Float/1" hermiteInterp (1 :: Float) = 1
"hermiteInterp/Double/1" hermiteInterp (1 :: Double) = 1
  #-}

-- | quintic interpolation
quinticInterp :: (Num a) => a -> a
quinticInterp t = t * t * t * (t * (t * 6 - 15) + 10)
{-# INLINE [1] quinticInterp #-}

{-# RULES
"quinticInterp/Float/0"
  quinticInterp (0 :: Float) =
    0
"quinticInterp/Double/0"
  quinticInterp (0 :: Double) =
    0
"quinticInterp/Float/1"
  quinticInterp (1 :: Float) =
    1
"quinticInterp/Double/1"
  quinticInterp (1 :: Double) =
    1
  #-}

-- | Clamp a value to a specified range.
--
-- Returns the value if it's within bounds, otherwise returns
-- the nearest boundary.
clamp
  :: (Ord a)
  => a
  -- ^ lower bound
  -> a
  -- ^ upper bound
  -> a
  -- ^ value
  -> a
clamp l u v = min (max v l) u
{-# INLINE clamp #-}

primeX, primeY, primeZ :: Hash
primeX = 501125321
{-# INLINE primeX #-}
primeY = 1136930381
{-# INLINE primeY #-}
primeZ = 1720413743
{-# INLINE primeZ #-}

hash2 :: Seed -> Hash -> Hash -> Hash
hash2 seed xPrimed yPrimed =
  (fromIntegral seed `xor` xPrimed `xor` yPrimed)
    * 0x27d4eb2d
{-# INLINE hash2 #-}

hash3 :: Seed -> Hash -> Hash -> Hash -> Hash
hash3 seed xPrimed yPrimed zPrimed =
  (fromIntegral seed `xor` xPrimed `xor` yPrimed `xor` zPrimed)
    * 0x27d4eb2d
{-# INLINE hash3 #-}

infinity :: (Fractional a) => a
infinity = 1 / 0
{-# INLINE infinity #-}

g2 :: (Fractional a) => a
g2 = (3 - sqrt3) / 6
{-# INLINE g2 #-}

sqrt3 :: (Fractional a) => a
sqrt3 = 1.7320508075688772935274463415059
{-# INLINE sqrt3 #-}

valCoord2 :: (RealFrac a) => Seed -> Hash -> Hash -> a
valCoord2 seed xPrimed yPrimed =
  let !hash = hash2 seed xPrimed yPrimed
      !val = (hash * hash) `xor` (hash `shiftL` 19)
   in fromIntegral val * recip (maxHash + 1)
{-# INLINE valCoord2 #-}

valCoord3 :: (RealFrac a) => Seed -> Hash -> Hash -> Hash -> a
valCoord3 seed xPrimed yPrimed zPrimed =
  let !hash = hash3 seed xPrimed yPrimed zPrimed
      !val = (hash * hash) `xor` (hash `shiftL` 19)
   in fromIntegral val * recip (maxHash + 1)
{-# INLINE valCoord3 #-}

gradCoord2 :: (RealFrac a) => Seed -> Hash -> Hash -> a -> a -> a
gradCoord2 seed xPrimed yPrimed xd yd =
  let !hash = hash2 seed xPrimed yPrimed
      !ix = (hash `xor` (hash `shiftR` 15)) .&. 0xFE
      !xg = lookupGrad2 ix
      !yg = lookupGrad2 (ix .|. 1)
   in xd * xg + yd * yg
-- Phase 2 inlining ensures specialization happens after hash computation
-- but before gradient lookup, allowing REWRITE RULES to fire effectively
{-# INLINE [2] gradCoord2 #-}

gradCoord3 :: (RealFrac a) => Seed -> Hash -> Hash -> Hash -> a -> a -> a -> a
gradCoord3 seed xPrimed yPrimed zPrimed xd yd zd =
  let !hash = hash3 seed xPrimed yPrimed zPrimed
      !ix = (hash `xor` (hash `shiftR` 15)) .&. 0xFC
      !xg = lookupGrad3 ix
      !yg = lookupGrad3 (ix .|. 1)
      !zg = lookupGrad3 (ix .|. 2)
   in xd * xg + yd * yg + zd * zg
{-# INLINE gradCoord3 #-}

maxHash :: (RealFrac a) => a
maxHash = fromIntegral (maxBound @Hash)
{-# INLINE maxHash #-}

lookupGrad2 :: (RealFrac a) => Hash -> a
lookupGrad2 = realToFrac . (grad2dd `indexPrimArray`) . fromIntegral
{-# INLINE [0] lookupGrad2 #-}

{-# RULES
"lookupGrad2/Float" forall (i :: Hash).
  lookupGrad2 i =
    indexPrimArray grad2df (fromIntegral i)
"lookupGrad2/Double" forall (i :: Hash).
  lookupGrad2 i =
    indexPrimArray grad2dd (fromIntegral i)
  #-}

grad2df :: PrimArray Float
grad2df = mapPrimArray realToFrac grad2dd

{- ORMOLU_DISABLE -}
-- >>> sizeofPrimArray grad2d == 256
-- True
grad2dd :: PrimArray Double
grad2dd =
  [ 0.130526192220052,  0.99144486137381 ,  0.38268343236509 ,  0.923879532511287,  0.608761429008721,  0.793353340291235,  0.793353340291235,  0.608761429008721,
    0.923879532511287,  0.38268343236509 ,  0.99144486137381 ,  0.130526192220051,  0.99144486137381 , -0.130526192220051,  0.923879532511287, -0.38268343236509,
    0.793353340291235, -0.60876142900872 ,  0.608761429008721, -0.793353340291235,  0.38268343236509 , -0.923879532511287,  0.130526192220052, -0.99144486137381,
   -0.130526192220052, -0.99144486137381 , -0.38268343236509 , -0.923879532511287, -0.608761429008721, -0.793353340291235, -0.793353340291235, -0.608761429008721,
   -0.923879532511287, -0.38268343236509 , -0.99144486137381 , -0.130526192220052, -0.99144486137381 ,  0.130526192220051, -0.923879532511287,  0.38268343236509,
   -0.793353340291235,  0.608761429008721, -0.608761429008721,  0.793353340291235, -0.38268343236509 ,  0.923879532511287, -0.130526192220052,  0.99144486137381,
    0.130526192220052,  0.99144486137381 ,  0.38268343236509 ,  0.923879532511287,  0.608761429008721,  0.793353340291235,  0.793353340291235,  0.608761429008721,
    0.923879532511287,  0.38268343236509 ,  0.99144486137381 ,  0.130526192220051,  0.99144486137381 , -0.130526192220051,  0.923879532511287, -0.38268343236509,
    0.793353340291235, -0.60876142900872 ,  0.608761429008721, -0.793353340291235,  0.38268343236509 , -0.923879532511287,  0.130526192220052, -0.99144486137381,
   -0.130526192220052, -0.99144486137381 , -0.38268343236509 , -0.923879532511287, -0.608761429008721, -0.793353340291235, -0.793353340291235, -0.608761429008721,
   -0.923879532511287, -0.38268343236509 , -0.99144486137381 , -0.130526192220052, -0.99144486137381 ,  0.130526192220051, -0.923879532511287,  0.38268343236509,
   -0.793353340291235,  0.608761429008721, -0.608761429008721,  0.793353340291235, -0.38268343236509 ,  0.923879532511287, -0.130526192220052,  0.99144486137381,
    0.130526192220052,  0.99144486137381 ,  0.38268343236509 ,  0.923879532511287,  0.608761429008721,  0.793353340291235,  0.793353340291235,  0.608761429008721,
    0.923879532511287,  0.38268343236509 ,  0.99144486137381 ,  0.130526192220051,  0.99144486137381 , -0.130526192220051,  0.923879532511287, -0.38268343236509,
    0.793353340291235, -0.60876142900872 ,  0.608761429008721, -0.793353340291235,  0.38268343236509 , -0.923879532511287,  0.130526192220052, -0.99144486137381,
   -0.130526192220052, -0.99144486137381 , -0.38268343236509 , -0.923879532511287, -0.608761429008721, -0.793353340291235, -0.793353340291235, -0.608761429008721,
   -0.923879532511287, -0.38268343236509 , -0.99144486137381 , -0.130526192220052, -0.99144486137381 ,  0.130526192220051, -0.923879532511287,  0.38268343236509,
   -0.793353340291235,  0.608761429008721, -0.608761429008721,  0.793353340291235, -0.38268343236509 ,  0.923879532511287, -0.130526192220052,  0.99144486137381,
    0.130526192220052,  0.99144486137381 ,  0.38268343236509 ,  0.923879532511287,  0.608761429008721,  0.793353340291235,  0.793353340291235,  0.608761429008721,
    0.923879532511287,  0.38268343236509 ,  0.99144486137381 ,  0.130526192220051,  0.99144486137381 , -0.130526192220051,  0.923879532511287, -0.38268343236509,
    0.793353340291235, -0.60876142900872 ,  0.608761429008721, -0.793353340291235,  0.38268343236509 , -0.923879532511287,  0.130526192220052, -0.99144486137381,
   -0.130526192220052, -0.99144486137381 , -0.38268343236509 , -0.923879532511287, -0.608761429008721, -0.793353340291235, -0.793353340291235, -0.608761429008721,
   -0.923879532511287, -0.38268343236509 , -0.99144486137381 , -0.130526192220052, -0.99144486137381 ,  0.130526192220051, -0.923879532511287,  0.38268343236509,
   -0.793353340291235,  0.608761429008721, -0.608761429008721,  0.793353340291235, -0.38268343236509 ,  0.923879532511287, -0.130526192220052,  0.99144486137381,
    0.130526192220052,  0.99144486137381 ,  0.38268343236509 ,  0.923879532511287,  0.608761429008721,  0.793353340291235,  0.793353340291235,  0.608761429008721,
    0.923879532511287,  0.38268343236509 ,  0.99144486137381 ,  0.130526192220051,  0.99144486137381 , -0.130526192220051,  0.923879532511287, -0.38268343236509,
    0.793353340291235, -0.60876142900872 ,  0.608761429008721, -0.793353340291235,  0.38268343236509 , -0.923879532511287,  0.130526192220052, -0.99144486137381,
   -0.130526192220052, -0.99144486137381 , -0.38268343236509 , -0.923879532511287, -0.608761429008721, -0.793353340291235, -0.793353340291235, -0.608761429008721,
   -0.923879532511287, -0.38268343236509 , -0.99144486137381 , -0.130526192220052, -0.99144486137381 ,  0.130526192220051, -0.923879532511287,  0.38268343236509,
   -0.793353340291235,  0.608761429008721, -0.608761429008721,  0.793353340291235, -0.38268343236509 ,  0.923879532511287, -0.130526192220052,  0.99144486137381,
    0.38268343236509 ,  0.923879532511287,  0.923879532511287,  0.38268343236509 ,  0.923879532511287, -0.38268343236509 ,  0.38268343236509 , -0.923879532511287,
   -0.38268343236509 , -0.923879532511287, -0.923879532511287, -0.38268343236509 , -0.923879532511287,  0.38268343236509 , -0.38268343236509 ,  0.923879532511287
  ]

{- ORMOLU_ENABLE -}

lookupGrad3 :: (RealFrac a) => Hash -> a
lookupGrad3 = realToFrac . (grad3dd `indexPrimArray`) . fromIntegral
{-# INLINE [0] lookupGrad3 #-}

{-# RULES
"lookupGrad3/Float" forall (i :: Hash).
  lookupGrad3 i =
    indexPrimArray grad3df (fromIntegral i)
"lookupGrad3/Double" forall (i :: Hash).
  lookupGrad3 i =
    indexPrimArray grad3dd (fromIntegral i)
  #-}

grad3df :: PrimArray Float
grad3df = mapPrimArray realToFrac grad3dd

{- ORMOLU_DISABLE -}
-- >>> sizeofPrimArray grad3d == 256
-- True
grad3dd :: PrimArray Double
grad3dd =
  [ 0, 1, 1, 0, 0, -1, 1, 0, 0, 1, -1, 0, 0, -1, -1, 0
  , 1, 0, 1, 0, -1, 0, 1, 0, 1, 0, -1, 0, -1, 0, -1, 0
  , 1, 1, 0, 0, -1, 1, 0, 0, 1, -1, 0, 0, -1, -1, 0, 0
  , 0, 1, 1, 0, 0, -1, 1, 0, 0, 1, -1, 0, 0, -1, -1, 0
  , 1, 0, 1, 0, -1, 0, 1, 0, 1, 0, -1, 0, -1, 0, -1, 0
  , 1, 1, 0, 0, -1, 1, 0, 0, 1, -1, 0, 0, -1, -1, 0, 0
  , 0, 1, 1, 0, 0, -1, 1, 0, 0, 1, -1, 0, 0, -1, -1, 0
  , 1, 0, 1, 0, -1, 0, 1, 0, 1, 0, -1, 0, -1, 0, -1, 0
  , 1, 1, 0, 0, -1, 1, 0, 0, 1, -1, 0, 0, -1, -1, 0, 0
  , 0, 1, 1, 0, 0, -1, 1, 0, 0, 1, -1, 0, 0, -1, -1, 0
  , 1, 0, 1, 0, -1, 0, 1, 0, 1, 0, -1, 0, -1, 0, -1, 0
  , 1, 1, 0, 0, -1, 1, 0, 0, 1, -1, 0, 0, -1, -1, 0, 0
  , 0, 1, 1, 0, 0, -1, 1, 0, 0, 1, -1, 0, 0, -1, -1, 0
  , 1, 0, 1, 0, -1, 0, 1, 0, 1, 0, -1, 0, -1, 0, -1, 0
  , 1, 1, 0, 0, -1, 1, 0, 0, 1, -1, 0, 0, -1, -1, 0, 0
  , 1, 1, 0, 0, 0, -1, 1, 0, -1, 1, 0, 0, 0, -1, -1, 0
  ]