packages feed

sloane-2.0.1: Sloane/Transform.hs

-- |
-- Copyright   : Anders Claesson 2012-2015
-- Maintainer  : Anders Claesson <anders.claesson@gmail.com>
-- License     : BSD-3
--
module Sloane.Transform
    ( NamedTransform (..)
    , ($$)
    , tLEFT
    , tRIGHT
    , tM2
    , tM2i
    , tBINOMIAL
    , tBINOMIALi
    , tBIN1
    , tBISECT0
    , tBISECT1
    , tCONV
    , tCONVi
    , tEXPCONV
    , tDIFF
    , tMOBIUS
    , tMOBIUSi
    , tEULER
    , tEXP
    , tLOG
    , tNEGATE
    , tPRODS
    , tPSUM
    , tPSUMSIGN
    , tSTIRLING
    , tTRISECT0
    , tTRISECT1
    , tTRISECT2
    , tPOINT
    , tWEIGHT
    , tPARTITION
    , transforms
    , lookupTranform
    , applyAllTransforms
    ) where

import Data.List
import Data.Ratio
import Data.Monoid
import Control.Monad
import Sloane.GF

type Transform = [Rational] -> [Rational]

data NamedTransform = NT
    { name :: String
    , eval :: Transform
    }

instance Show NamedTransform where
    show = ('t':) . name

instance Eq NamedTransform where
    t == s = name t == name s

instance Monoid NamedTransform where
    mempty = NT "" id
    mappend f g = NT tname teval
      where
        tname = name f ++ "." ++ name g
        teval = eval f     .     eval g

infixr 0 $$

isInteger :: Rational -> Bool
isInteger = (1==) . denominator

toIntSeq :: [Rational] -> [Integer]
toIntSeq cs = [ numerator c | c <- cs, all isInteger cs ]

($$) :: NamedTransform -> [Integer] -> [Integer]
f $$ cs = toIntSeq $ take (length cs) (eval f (map toRational cs))

x :: GF
x = ogf [0::Integer, 1]

-- addSeq :: [Integer] -> Transform
-- addSeq seq0 = zipWith (+) seq0

-- mulOGF :: [Integer] -> Transform
-- mulOGF seq0 = \cs -> ogfCoeffs (ogf seq0 * ogf cs)

-- mulEGF :: [Integer] -> Transform
-- mulEGF seq0 = \cs -> egfCoeffs (egf seq0 * egf cs)

geoSeries :: Rational -> GF
geoSeries c = ogf [ c^k | k<-[0::Int ..] ]

expSeries :: Rational -> GF
expSeries c = egf [ c^k | k<-[0::Int ..] ]

bisect0 :: [a] -> [a]
bisect0 [] = []
bisect0 (c:cs) = c : bisect1 cs

bisect1 :: [a] -> [a]
bisect1 [] = []
bisect1 (_:cs) = bisect0 cs

trisect0 :: [a] -> [a]
trisect0 [] = []
trisect0 (c:cs) = c : trisect2 cs

trisect1 :: [a] -> [a]
trisect1 [] = []
trisect1 (_:cs) = trisect0 cs

trisect2 :: [a] -> [a]
trisect2 [] = []
trisect2 (_:cs) = trisect1 cs

signed :: GF -> GF
signed = imap $ \i c -> (-1%1)^i * c

tLEFT :: NamedTransform
tLEFT = NT "LEFT" (drop 1)

tRIGHT :: NamedTransform
tRIGHT = NT "RIGHT" (1:)

tM2 :: NamedTransform
tM2 = NT "M2" f where f [] = []; f (c:cs) = c : map ((2%1)*) cs

tM2i :: NamedTransform
tM2i = NT "M2i" (\cs -> ogfCoeffs (Series (f cs)))
  where
    f [] = []
    f cs = let (d:ds) = map toRational cs in d : map (/(2%1)) ds

tBINOMIAL :: NamedTransform
tBINOMIAL = NT "BINOMIAL" (\cs -> egfCoeffs (expSeries (1%1) * egf cs))

tBINOMIALi :: NamedTransform
tBINOMIALi = NT "BINOMIALi" (\cs -> egfCoeffs (expSeries ((-1)%1) * egf cs))

tBIN1 :: NamedTransform
tBIN1 = NT "BIN1" (\cs ->
    drop 1 . egfCoeffs $ -expSeries (-1%1) * signed (egf (0:cs)))

tBISECT0 :: NamedTransform
tBISECT0 = NT "BISECT0" bisect0

tBISECT1 :: NamedTransform
tBISECT1 = NT "BISECT1" bisect1

tCONV :: NamedTransform
tCONV = NT "CONV" (\cs -> ogfCoeffs (ogf cs ^ (2::Int)))

tCONVi :: NamedTransform
tCONVi = NT "CONVi" (\cs -> ogfCoeffs (squareRoot (ogf cs)))

tEXPCONV :: NamedTransform
tEXPCONV = NT "EXPCONV" (\cs -> egfCoeffs (egf cs ^ (2::Int)))

tDIFF :: NamedTransform
tDIFF = NT "DIFF" (\cs -> zipWith (-) (drop 1 cs) cs)

-- The Mobius function of the poset of integers under divisibility
mobius :: Integer -> Integer -> Integer
mobius a b
  | a == b         = 1
  | b `rem` a == 0 = -sum [ mobius a c | c <- [a..b-1], b `rem` c == 0 ]
  | otherwise      = 0

-- The number theoretical Mobius function
mu :: Integer -> Integer
mu = mobius 1

tMOBIUS :: NamedTransform
tMOBIUS = NT "MOBIUS" $ \cs ->
    [ sum [mu (n `div` k) % 1 * (cs !! (fromInteger k-1))
          | k<-[1..n], n `rem` k == 0
          ]
    | (n,_) <- zip [1..] cs
    ]

tMOBIUSi :: NamedTransform
tMOBIUSi = NT "MOBIUSi" $ \cs ->
    [ sum [ (cs !! (fromInteger k-1)) | k<-[1..n], n `rem` k == 0 ]
    | (n,_) <- zip [1..] cs
    ]

tEULER :: NamedTransform
tEULER = NT "EULER" (\cs ->
    let f = product $ zipWith (\n c -> (1 - x^n)^^^c) [1::Int ..] cs
    in drop 1 $ ogfCoeffs (1/f))

tEULERi :: NamedTransform
tEULERi = NT "EULERi" undefined

-- EXP converts [a_1, a_2, ...] to [b_1, b_2,...] where
-- 1 + EGF_B (x) = exp EGF_A (x)
tEXP :: NamedTransform
tEXP = NT "EXP" (\cs -> drop 1 . egfCoeffs $ expSeries 1 `o` egf (0:cs))

-- LOG converts [a_1, a_2, ...] to [b_1, b_2,...] where
-- 1 + EGF_A (x) = exp EGF_B (x) i.e. EGF_B (x) = log(1 + EGF_A (x)).
tLOG :: NamedTransform
tLOG = NT "LOG" (\cs -> drop 1 $ egfCoeffs (log1 `o` (-1 * egf (0:cs))))
  where
    log1 = Series (0 : [-1 % n | n <- [1..]])

tNEGATE :: NamedTransform
tNEGATE = NT "NEGATE" f where f [] = []; f (c:cs) = c : map negate cs

tPRODS :: NamedTransform
tPRODS = NT "PRODS" (drop 1 . scanl (*) (1%1))

tPSUM :: NamedTransform
tPSUM = NT "PSUM" (drop 1 . scanl (+) (0%1))

tPSUMSIGN :: NamedTransform
tPSUMSIGN = NT "PSUMSIGN" (ogfCoeffs . (geoSeries (-1%1) *) . ogf)

tSTIRLING :: NamedTransform
tSTIRLING = NT "STIRLING" (\cs ->
    drop 1 . egfCoeffs $ egf (0:cs) `o` (expSeries (1%1) - 1))

tTRISECT0 :: NamedTransform
tTRISECT0 = NT "TRISECT0" trisect0

tTRISECT1 :: NamedTransform
tTRISECT1 = NT "TRISECT1" trisect1

tTRISECT2 :: NamedTransform
tTRISECT2 = NT "TRISECT2" trisect2

tPOINT :: NamedTransform
tPOINT = NT "POINT" (zipWith (*) [0..])

tWEIGHT :: NamedTransform
tWEIGHT = NT "WEIGHT" $
    drop 1 . ogfCoeffs . product . zipWith (\n c -> (1 + x^n)^^^c) [1::Int ..]

increasing :: Ord a => [a] -> Bool
increasing cs = and $ zipWith (<=) cs (drop 1 cs)

tPARTITION :: NamedTransform
tPARTITION = NT "PARTITION" $ \cs -> do
    guard $ not (null cs) && all (>0) cs && increasing cs
    let f = product $ map (\c -> (1 - x^^^c)) (nub cs)
    drop 1 . ogfCoeffs $ 1/f

-- New transform: tSTIELTJES -- continued fraction coefficients


transforms :: [NamedTransform]
transforms =
    [ tLEFT
    , tRIGHT
    , tM2
    , tM2i
    , tBINOMIAL
    , tBINOMIALi
    , tBIN1
    , tBISECT0
    , tBISECT1
    , tCONV
    , tCONVi
    , tEXPCONV
    , tDIFF
    , tMOBIUS
    , tMOBIUSi
    , tEULER
--    , tEULERi
    , tEXP
    , tLOG
    , tNEGATE
    , tPRODS
    , tPSUM
    , tPSUMSIGN
    , tSTIRLING
    , tTRISECT0
    , tTRISECT1
    , tTRISECT2
    , tPOINT
    , tWEIGHT
    , tPARTITION
    ]

lookupTranform :: String -> Maybe NamedTransform
lookupTranform tname = lookup tname [ (name f, f) | f <- transforms ]

applyAllTransforms :: [Rational] -> [(NamedTransform, [Rational])]
applyAllTransforms cs = [ (f, eval f cs) | f <- transforms ]