interpolation 0.1.1.1 → 0.1.1.2
raw patch · 17 files changed
+528/−203 lines, 17 filesdep +comfort-array-shapedep +doctest-exitcode-stdiodep +doctest-libdep ~comfort-arraydep ~containersdep ~lapackPVP ok
version bump matches the API change (PVP)
Dependencies added: comfort-array-shape, doctest-exitcode-stdio, doctest-lib
Dependency ranges changed: comfort-array, containers, lapack, random
API changes (from Hackage documentation)
Files
- ChangeLog +4/−0
- Makefile +8/−0
- example/Fit.hs +34/−32
- interpolation.cabal +22/−12
- src/Numeric/Interpolation/NodeList.hs +38/−0
- src/Numeric/Interpolation/Piece.hs +26/−1
- src/Numeric/Interpolation/Piecewise.hs +71/−0
- src/Numeric/Interpolation/Type.hs +27/−0
- test-module.list +4/−0
- test/Test.hs +11/−11
- test/Test/Numeric/Interpolation/NodeList.hs +79/−0
- test/Test/Numeric/Interpolation/Piece.hs +43/−0
- test/Test/Numeric/Interpolation/Piecewise.hs +119/−0
- test/Test/Numeric/Interpolation/Type.hs +42/−0
- test/Test/Overlap.hs +0/−25
- test/Test/Piece.hs +0/−60
- test/Test/Sample.hs +0/−62
ChangeLog view
@@ -1,3 +1,7 @@+0.1.1.2:++* add testsuite based on doctest comments and doctest-extract+ 0.1: * Hermite1 interpolation: different order of coefficients
+ Makefile view
@@ -0,0 +1,8 @@+run-test: update-test+ runhaskell Setup configure --user --enable-test -fbuildExamples -flapack+ runhaskell Setup build+ runhaskell Setup haddock+ runhaskell Setup test --show-details=always++update-test:+ doctest-extract -i src/ -o test/ --module-prefix Test --executable-main=Test.hs $$(cat test-module.list)
example/Fit.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE TypeFamilies #-} {-# LANGUAGE Rank2Types #-} module Main where @@ -8,19 +9,23 @@ import qualified Numeric.Interpolation.Type as Type import qualified Numeric.LAPACK.Singular as Singular-import qualified Numeric.LAPACK.ShapeStatic as ShapeStatic import qualified Numeric.LAPACK.Matrix.Shape as MatrixShape import qualified Numeric.LAPACK.Matrix.BandedHermitianPositiveDefinite as BandedSPD import qualified Numeric.LAPACK.Matrix.BandedHermitian as BandedHermitian+import qualified Numeric.LAPACK.Matrix.Banded as Banded import qualified Numeric.LAPACK.Matrix.Array as ArrMatrix import qualified Numeric.LAPACK.Matrix as Matrix import qualified Numeric.LAPACK.Vector as Vector+import Numeric.LAPACK.Matrix ((#\|))+import Numeric.LAPACK.Vector (Vector) import qualified Type.Data.Num.Unary as Unary import Type.Base.Proxy (Proxy) import qualified Data.Array.Comfort.Storable as Array+import qualified Data.Array.Comfort.Container as Container+import qualified Data.Array.Comfort.Shape.Static as ShapeStatic import qualified Data.Array.Comfort.Shape as Shape import qualified Graphics.Gnuplot.Advanced as GP@@ -39,11 +44,11 @@ import Data.Monoid ((<>)) -type BandedHermitianMatrix k =- BandedHermitian.BandedHermitian k Matrix.ShapeInt-type Matrix = Matrix.General Matrix.ShapeInt Matrix.ShapeInt-type Vector = Vector.Vector Matrix.ShapeInt-type ShortVector k = Vector.Vector (ShapeStatic.ZeroBased k)+{- |+We use @'Container.Shape' []@ for distinction.+We could use 'Matrix.ShapeInt' as well.+-}+type BasicMatrix = Matrix.General Matrix.ShapeInt (Container.Shape []) noisy :: [(Double, Double)]@@ -55,24 +60,23 @@ (randomRs (-0.2,0.2) (mkStdGen 42)) basisMatrixFull ::- Type.T Double Double ny -> [Double] -> [Double] -> Matrix Double+ Type.T Double Double ny -> [Double] -> [Double] -> BasicMatrix Double basisMatrixFull typ xs txs0 = let txs = Vector.autoFromList txs0- in Matrix.fromColumns (Array.shape txs) $+ in Matrix.fromColumnContainer (Array.shape txs) $ map (flip Array.map txs . Piecewise.interpolateConstantExt typ) $ Type.basisFunctions typ xs zipRowsWith :: (a -> b -> c) -> [a] -> [[b]] -> [c] zipRowsWith f as bs = concat $ zipWith (map . f) as bs --- ToDo: generalize shapes basisMatrixSparse ::- Type.T Double Double ny -> [Double] -> [Double] -> Matrix Double+ Type.T Double Double ny -> [Double] -> [Double] -> BasicMatrix Double basisMatrixSparse typ xs txs = Matrix.fromRowMajor $ Array.fromAssociations 0 (Shape.ZeroBased $ length txs,- Shape.ZeroBased $ length $ Type.basisFunctions typ xs) $+ Container.toShape $ Type.basisFunctions typ xs) $ zipRowsWith (\k (j,x) -> ((k,j),x)) [0..] $ map (Type.sampleBasisFunctions typ xs) txs @@ -99,34 +103,31 @@ mulSparseMatrixVector ::- Int -> [[(Int, Double)]] -> [Double] -> Vector Double-mulSparseMatrixVector size samples tys =+ (Shape.Indexed shape) =>+ shape -> [[(Shape.Index shape, Double)]] ->+ [Double] -> Vector shape Double+mulSparseMatrixVector shape samples tys = Array.accumulate (+)- (Vector.zero (Matrix.shapeInt size))+ (Vector.zero shape) (zipRowsWith (\ty (k,y) -> (k, y*ty)) tys samples) -{- ToDo:-use index type (ZeroInt, Enumeration Order)-with Order = Absolute | Derivative-Problem: not all interpolation types use derivatives--} shortVector :: (Unary.Natural k) =>- Proxy k -> [(Int, Double)] -> (Int, ShortVector k Double)+ Proxy k -> [(Int, Double)] -> (Int, Vector (ShapeStatic.ZeroBased k) Double) shortVector width xs = let i0 = minimum $ map fst xs in (i0,--- Array.fromAssociations 0 Shape.static $ Array.reshape Shape.static $- Array.fromAssociations 0 (Matrix.shapeInt $ Unary.integralFromProxy width) $+ Array.fromAssociations 0+ (Matrix.shapeInt $ Unary.integralFromProxy width) $ map (mapFst (subtract i0)) xs) bandedGramian ::- (Unary.Natural k) =>- Int -> Proxy (Unary.Succ k) ->- [[(Int, Double)]] -> BandedHermitianMatrix k Double-bandedGramian size width samples =- BandedHermitian.sumRank1 MatrixShape.ColumnMajor (Matrix.shapeInt size) $+ (Shape.Indexed shape, Shape.Index shape ~ Int, Unary.Natural k) =>+ shape -> Proxy (Unary.Succ k) ->+ [[(Int, Double)]] -> Banded.HermitianPosSemidef k shape Double+bandedGramian shape width samples =+ BandedHermitian.sumRank1 MatrixShape.ColumnMajor shape $ map ((,) 1 . shortVector width) samples reifyPositive ::@@ -137,15 +138,16 @@ Type.T Double Double ny -> [Double] -> [(Double, Double)] -> Nodes.T Double ny fitBanded typ xs target =- let size = length $ Type.basisFunctions typ xs+ let shape = Container.toShape $ Type.basisFunctions typ xs (txs, tys) = unzip target samples = map (Type.sampleBasisFunctions typ xs) txs- in reifyPositive (toInteger $ Type.basisOverlap typ) + in reifyPositive+ (toInteger $ Type.basisOverlap typ) (\width -> Type.coefficientsToInterpolator typ xs $ Vector.toList $- Matrix.unliftColumn MatrixShape.ColumnMajor- (BandedSPD.solve (bandedGramian size width samples)) $- mulSparseMatrixVector size samples tys)+ BandedSPD.assureFullRank (bandedGramian shape width samples)+ #\|+ mulSparseMatrixVector shape samples tys) bandedDiff :: (ny -> ny -> Double) ->
interpolation.cabal view
@@ -1,10 +1,11 @@+Cabal-Version: 2.2 Name: interpolation-Version: 0.1.1.1-License: BSD3+Version: 0.1.1.2+License: BSD-3-Clause License-File: LICENSE Author: Henning Thielemann Maintainer: Henning Thielemann <haskell@henning-thielemann.de>-Homepage: http://hub.darcs.net/thielema/interpolation/+Homepage: https://hub.darcs.net/thielema/interpolation/ Category: Math Synopsis: piecewise linear and cubic Hermite interpolation Description:@@ -33,10 +34,11 @@ Most of the package dependencies are only needed for the examples and are only installed if you enable to build them. Tested-With: GHC==7.4.2, GHC==7.6.3, GHC==7.8.4, GHC==7.10.1-Cabal-Version: >=1.8 Build-Type: Simple Extra-Source-Files: ChangeLog+ Makefile+ test-module.list Flag buildExamples description: Build example executables@@ -47,13 +49,13 @@ default: True Source-Repository this- Tag: 0.1.1.1+ Tag: 0.1.1.2 Type: darcs- Location: http://hub.darcs.net/thielema/interpolation/+ Location: https://hub.darcs.net/thielema/interpolation/ Source-Repository head Type: darcs- Location: http://hub.darcs.net/thielema/interpolation/+ Location: https://hub.darcs.net/thielema/interpolation/ Library Build-Depends:@@ -62,6 +64,7 @@ GHC-Options: -Wall Hs-Source-Dirs: src, private+ Default-Language: Haskell98 Exposed-Modules: Numeric.Interpolation.NodeList Numeric.Interpolation.Piece@@ -81,6 +84,7 @@ Other-Modules: Plot2DExtra Hs-Source-Dirs: example GHC-Options: -Wall+ Default-Language: Haskell98 If flag(buildExamples) Build-Depends: interpolation,@@ -95,12 +99,14 @@ Other-Modules: Plot2DExtra Hs-Source-Dirs: example GHC-Options: -Wall+ Default-Language: Haskell98 If flag(buildExamples) && flag(lapack) Build-Depends: interpolation,- lapack >=0.3 && <0.4,+ lapack >=0.4 && <0.5, tfp >=1.0 && <1.1,- comfort-array >=0.4 && <0.5,+ comfort-array-shape >=0.0 && <0.1,+ comfort-array >=0.5.1 && <0.6, random >=1.0 && <1.2, gnuplot >=0.5.6 && <0.6, utility-ht >=0.0.9 && <0.1,@@ -112,14 +118,18 @@ Type: exitcode-stdio-1.0 Main-Is: Test.hs Other-Modules:- Test.Piece- Test.Sample- Test.Overlap+ Test.Numeric.Interpolation.Type+ Test.Numeric.Interpolation.NodeList+ Test.Numeric.Interpolation.Piece+ Test.Numeric.Interpolation.Piecewise Numeric.Interpolation.Private.Piece Hs-Source-Dirs: test, private GHC-Options: -Wall+ Default-Language: Haskell98 Build-Depends: interpolation,+ doctest-exitcode-stdio >=0.0 && <0.1,+ doctest-lib >=0.1 && <0.2, QuickCheck >=2.4 && <3, utility-ht >=0.0.9 && <0.1, array >=0.4 && <0.6,
src/Numeric/Interpolation/NodeList.hs view
@@ -16,22 +16,40 @@ import Prelude hiding (lookup) +{- $setup+>>> import qualified Numeric.Interpolation.NodeList as Nodes+>>> import qualified Data.Traversable as Trav+>>> import qualified Data.Foldable as Fold+>>> import qualified Data.List as List+>>> import Data.Tuple.HT (mapSnd)+>>> import Data.Char (ord)+-} + data T x y = Interval | Node (x, y) (T x y) (T x y) deriving (Eq, Ord, Show) +{- |+prop> \xs -> map (mapSnd ord) xs == Nodes.toList (fmap ord (Nodes.fromList (xs::[(Integer,Char)])))+-} instance Functor (T x) where fmap f = let go Interval = Interval go (Node (x,y) l r) = Node (x, f y) (go l) (go r) in go +{- |+prop> \xs -> map snd xs == Fold.toList (Nodes.fromList (xs::[(Integer,Char)]))+-} instance Foldable (T x) where foldMap f = let go Interval = mempty go (Node (_x,y) l r) = go l <> f y <> go r in go +{- |+prop> \x xs -> let f acc y = (acc+y,acc) in List.mapAccumL f x (map snd xs) == mapSnd Fold.toList (Trav.mapAccumL f x (Nodes.fromList (xs::[(Int,Integer)])))+-} instance Traversable (T x) where traverse f = let go Interval = pure Interval@@ -55,15 +73,35 @@ rep (n,xyns) = if null xyns then n else rep $ merge n xyns in rep . merge Interval . map (flip (,) Interval) +{- |+prop> \x y -> Nodes.singleton x y == Nodes.fromList [(x,y)::(Integer,Char)]+-} singleton :: x -> y -> T x y singleton x y = Node (x,y) Interval Interval +{- |+prop> \xs -> xs == Nodes.toList (Nodes.fromList (xs::[(Integer,Char)]))+-} toList :: T x y -> [(x,y)] toList = let go Interval = [] go (Node p l r) = go l ++ p : go r in go +{- |+>>> Nodes.lookup (Nodes.fromList ([(0,'a'),(2::Int,'b')])) (-1)+(Nothing,Just (0,'a'))+>>> Nodes.lookup (Nodes.fromList ([(0,'a'),(2::Int,'b')])) 0+(Just (0,'a'),Just (2,'b'))+>>> Nodes.lookup (Nodes.fromList ([(0,'a'),(2::Int,'b')])) 1+(Just (0,'a'),Just (2,'b'))+>>> Nodes.lookup (Nodes.fromList ([(0,'a'),(2::Int,'b')])) 2+(Just (2,'b'),Nothing)+>>> Nodes.lookup (Nodes.fromList ([(0,'a'),(2::Int,'b')])) 3+(Just (2,'b'),Nothing)+>>> Nodes.lookup (Nodes.fromList ([(0,'a'),(2,'b'),(5::Int,'c')])) 3+(Just (2,'b'),Just (5,'c'))+-} lookup :: Ord x => T x y -> x -> (Maybe (x,y), Maybe (x,y)) lookup nodes0 x0 = let go lb rb Interval = (lb, rb)
src/Numeric/Interpolation/Piece.hs view
@@ -1,15 +1,40 @@ module Numeric.Interpolation.Piece ( Piece.T,- Piece.linear,+ linear, hermite1, ) where import qualified Numeric.Interpolation.Private.Piece as Piece +{- $setup+>>> import qualified Numeric.Interpolation.Piece as Piece+>>> import qualified Numeric.Interpolation.Private.Piece as PiecePriv+>>> import qualified Test.QuickCheck as QC+>>> import Test.QuickCheck ((==>))+>>>+>>> forAllDistinctPoints ::+>>> (Show a, QC.Arbitrary a, QC.Testable prop) =>+>>> ((Rational, a) -> (Rational, a) -> prop) -> QC.Property+>>> forAllDistinctPoints f =+>>> QC.forAll QC.arbitrary $ \p1@(x1,_) ->+>>> QC.forAll QC.arbitrary $ \p2@(x2,_) ->+>>> x1/=x2 ==> f p1 p2+-}+ {- |+prop> forAllDistinctPoints $ \p1 p2 x -> Piece.linear p1 p2 x == Piece.linear p2 p1 x+-}+linear :: (Fractional a) => Piece.T a a a+linear = Piece.linear++{- | Hermite interpolation with one derivative per node. That is, the interpolating polynomial is cubic.++prop> forAllDistinctPoints $ \p1 p2 x -> Piece.hermite1 p1 p2 x == Piece.hermite1 p2 p1 x+prop> forAllDistinctPoints $ \p1@(x1,y1) p2@(x2,y2) x -> Piece.linear p1 p2 x == let slope = (y2-y1)/(x2-x1) in Piece.hermite1 (x1, (y1,slope)) (x2, (y2,slope)) x+prop> forAllDistinctPoints $ \p1 p2 x -> Piece.hermite1 p1 p2 x == PiecePriv.hermite1 p1 p2 x -} hermite1 :: (Fractional a) => Piece.T a a (a, a) hermite1 (x0,(y0,dy0)) (x1,(y1,dy1)) x =
src/Numeric/Interpolation/Piecewise.hs view
@@ -7,8 +7,60 @@ import qualified Numeric.Interpolation.Type as Type +{- $setup+>>> import qualified Numeric.Interpolation.Piecewise as Piecewise+>>> import qualified Numeric.Interpolation.NodeList as Nodes+>>> import qualified Numeric.Interpolation.Type as Type+>>>+>>> import qualified Data.List as List+>>> import qualified Data.Set as Set+>>> import Data.Array (accumArray, listArray)+>>> import Data.List.HT (lengthAtLeast)+>>>+>>> import qualified Test.QuickCheck as QC+>>> import Test.QuickCheck ((==>))+>>>+>>> forAllSortedRatios ::+>>> (QC.Testable prop) => ([Rational] -> Rational -> prop) -> QC.Property+>>> forAllSortedRatios f =+>>> QC.forAll (fmap Set.toAscList QC.arbitrary) $ \nodeXs x ->+>>> f (map fromInteger nodeXs) (fromInteger x)+>>>+>>> checkEq ::+>>> (Ord x, Eq y, Num y) =>+>>> Type.T x y ny -> [x] -> x -> Bool+>>> checkEq typ nodeXs x =+>>> let ys =+>>> map+>>> (flip (Piecewise.interpolateConstantExt typ) x)+>>> (Type.basisFunctions typ nodeXs)+>>> bounds = (0, length ys - 1)+>>> in listArray bounds ys+>>> ==+>>> accumArray (flip const) 0 bounds+>>> (Type.sampleBasisFunctions typ nodeXs x)+>>>+>>> quantile :: (Show a, Ord a, Fractional a) => [a] -> a -> a+>>> quantile [] _ = error "quantile: empty list"+>>> quantile [y] _ = y+>>> quantile ys x =+>>> let len = fromIntegral (length ys - 1)+>>> in Piecewise.interpolateConstantExt Type.linear+>>> (Nodes.fromList $ zip (map (/ len) $ map fromInteger [0..]) $+>>> List.sort ys)+>>> x+-}++ {- | It is a checked error to interpolate outside of the range of nodes.++>>> Piecewise.interpolate Type.linear (Nodes.fromList [(0,0),(3,6),(5,10::Rational)]) 2+4 % 1+>>> Piecewise.interpolate Type.hermite1 (Nodes.fromList [(0,(0,0)),(3,(9,6)),(5,(25,10::Rational))]) 2+4 % 1+>>> Piecewise.interpolate Type.hermite1 (Nodes.fromList [(0,(1,-2)),(3,(4,4)),(5,(16,8::Rational))]) 2+1 % 1 -} interpolate :: (Ord x) => Type.T x y ny -> Nodes.T x ny -> x -> y interpolate typ ns x =@@ -19,6 +71,25 @@ {- | Outside the range of nodes the interpolation function takes the value of the respective border.++prop> forAllSortedRatios $ checkEq Type.linear+prop> forAllSortedRatios $ checkEq Type.hermite1+prop> forAllSortedRatios $ \nodeXs x -> lengthAtLeast 4 nodeXs ==> checkEq Type.cubicLinear nodeXs x+prop> forAllSortedRatios $ \nodeXs x -> lengthAtLeast 4 nodeXs ==> checkEq Type.cubicParabola nodeXs x+++Linear interpolation can be used to compute the median, a quartile+or any other quantile of a list of arbitrary numbers.++>>> quantile [2,5,3::Rational] 0.5+3 % 1+>>> quantile [2,5,3,7::Rational] 0.5+4 % 1+>>> quantile [2,5,3,7::Rational] 0.25+11 % 4++prop> \(QC.NonEmpty xs) -> quantile (xs::[Rational]) 0 == minimum xs+prop> \(QC.NonEmpty xs) -> quantile (xs::[Rational]) 1 == maximum xs -} interpolateConstantExt :: (Ord x) => Type.T x y ny -> Nodes.T x ny -> x -> y
src/Numeric/Interpolation/Type.hs view
@@ -13,6 +13,21 @@ import Numeric.Interpolation.Private.Basis (hermite1Split) +{- $setup+>>> import qualified Numeric.Interpolation.Type as Type+>>>+>>> checkOverlap :: Type.T Double y ny -> [Double] -> Double -> Bool+>>> checkOverlap typ xs xi =+>>> let samples = map fst $ Type.sampleBasisFunctions typ xs xi+>>> in all (< minimum samples + Type.basisOverlap typ) samples+>>>+>>> checkOverlapNotTotal :: Type.T Double y ny -> [Double] -> Double -> Bool+>>> checkOverlapNotTotal typ xs xi =+>>> let samples = map fst $ Type.sampleBasisFunctions typ xs xi+>>> in maximum samples - minimum samples < Type.basisOverlap typ+-}++ data T x y ny = Cons { ssvFromNodes :: [x] -> [y] -> String,@@ -27,6 +42,9 @@ valueFromNode :: ny -> y } +{- |+prop> checkOverlap Type.linear+-} linear :: (Fractional a, Ord a, Show a) => T a a a linear = Cons {@@ -40,6 +58,9 @@ valueFromNode = id } +{- |+prop> checkOverlap Type.hermite1+-} hermite1 :: (Fractional a, Ord a, Show a) => T a a (a, a) hermite1 = Cons {@@ -56,6 +77,9 @@ valueFromNode = fst } +{- |+prop> checkOverlap Type.cubicLinear+-} cubicLinear :: (Fractional a, Ord a, Show a) => T a a (a, a) cubicLinear = Cons {@@ -69,6 +93,9 @@ valueFromNode = fst } +{- |+prop> checkOverlap Type.cubicParabola+-} cubicParabola :: (Fractional a, Ord a, Show a) => T a a (a, a) cubicParabola = Cons {
+ test-module.list view
@@ -0,0 +1,4 @@+Numeric.Interpolation.Type+Numeric.Interpolation.NodeList+Numeric.Interpolation.Piece+Numeric.Interpolation.Piecewise
test/Test.hs view
@@ -1,16 +1,16 @@+-- Do not edit! Automatically created with doctest-extract. module Main where -import qualified Test.Piece as Piece-import qualified Test.Sample as Sample-import qualified Test.Overlap as Overlap-+import qualified Test.Numeric.Interpolation.Type+import qualified Test.Numeric.Interpolation.NodeList+import qualified Test.Numeric.Interpolation.Piece+import qualified Test.Numeric.Interpolation.Piecewise -run :: String -> [(String, IO ())] -> IO ()-run prefix =- mapM_ (\(msg,act) -> putStr (prefix ++ '.' : msg ++ ": ") >> act)+import qualified Test.DocTest.Driver as DocTest main :: IO ()-main = do- run "Piece" Piece.tests- run "Sample" Sample.tests- run "Overlap" Overlap.tests+main = DocTest.run $ do+ Test.Numeric.Interpolation.Type.test+ Test.Numeric.Interpolation.NodeList.test+ Test.Numeric.Interpolation.Piece.test+ Test.Numeric.Interpolation.Piecewise.test
+ test/Test/Numeric/Interpolation/NodeList.hs view
@@ -0,0 +1,79 @@+-- Do not edit! Automatically created with doctest-extract from src/Numeric/Interpolation/NodeList.hs+{-# LINE 19 "src/Numeric/Interpolation/NodeList.hs" #-}++module Test.Numeric.Interpolation.NodeList where++import Test.DocTest.Base+import qualified Test.DocTest.Driver as DocTest++{-# LINE 20 "src/Numeric/Interpolation/NodeList.hs" #-}+import qualified Numeric.Interpolation.NodeList as Nodes+import qualified Data.Traversable as Trav+import qualified Data.Foldable as Fold+import qualified Data.List as List+import Data.Tuple.HT (mapSnd)+import Data.Char (ord)++test :: DocTest.T ()+test = do+ DocTest.printPrefix "Numeric.Interpolation.NodeList:33: "+{-# LINE 33 "src/Numeric/Interpolation/NodeList.hs" #-}+ DocTest.property+{-# LINE 33 "src/Numeric/Interpolation/NodeList.hs" #-}+ (\xs -> map (mapSnd ord) xs == Nodes.toList (fmap ord (Nodes.fromList (xs::[(Integer,Char)]))))+ DocTest.printPrefix "Numeric.Interpolation.NodeList:42: "+{-# LINE 42 "src/Numeric/Interpolation/NodeList.hs" #-}+ DocTest.property+{-# LINE 42 "src/Numeric/Interpolation/NodeList.hs" #-}+ (\xs -> map snd xs == Fold.toList (Nodes.fromList (xs::[(Integer,Char)])))+ DocTest.printPrefix "Numeric.Interpolation.NodeList:51: "+{-# LINE 51 "src/Numeric/Interpolation/NodeList.hs" #-}+ DocTest.property+{-# LINE 51 "src/Numeric/Interpolation/NodeList.hs" #-}+ (\x xs -> let f acc y = (acc+y,acc) in List.mapAccumL f x (map snd xs) == mapSnd Fold.toList (Trav.mapAccumL f x (Nodes.fromList (xs::[(Int,Integer)]))))+ DocTest.printPrefix "Numeric.Interpolation.NodeList:77: "+{-# LINE 77 "src/Numeric/Interpolation/NodeList.hs" #-}+ DocTest.property+{-# LINE 77 "src/Numeric/Interpolation/NodeList.hs" #-}+ (\x y -> Nodes.singleton x y == Nodes.fromList [(x,y)::(Integer,Char)])+ DocTest.printPrefix "Numeric.Interpolation.NodeList:83: "+{-# LINE 83 "src/Numeric/Interpolation/NodeList.hs" #-}+ DocTest.property+{-# LINE 83 "src/Numeric/Interpolation/NodeList.hs" #-}+ (\xs -> xs == Nodes.toList (Nodes.fromList (xs::[(Integer,Char)])))+ DocTest.printPrefix "Numeric.Interpolation.NodeList:92: "+{-# LINE 92 "src/Numeric/Interpolation/NodeList.hs" #-}+ DocTest.example+{-# LINE 92 "src/Numeric/Interpolation/NodeList.hs" #-}+ (Nodes.lookup (Nodes.fromList ([(0,'a'),(2::Int,'b')])) (-1))+ [ExpectedLine [LineChunk "(Nothing,Just (0,'a'))"]]+ DocTest.printPrefix "Numeric.Interpolation.NodeList:94: "+{-# LINE 94 "src/Numeric/Interpolation/NodeList.hs" #-}+ DocTest.example+{-# LINE 94 "src/Numeric/Interpolation/NodeList.hs" #-}+ (Nodes.lookup (Nodes.fromList ([(0,'a'),(2::Int,'b')])) 0)+ [ExpectedLine [LineChunk "(Just (0,'a'),Just (2,'b'))"]]+ DocTest.printPrefix "Numeric.Interpolation.NodeList:96: "+{-# LINE 96 "src/Numeric/Interpolation/NodeList.hs" #-}+ DocTest.example+{-# LINE 96 "src/Numeric/Interpolation/NodeList.hs" #-}+ (Nodes.lookup (Nodes.fromList ([(0,'a'),(2::Int,'b')])) 1)+ [ExpectedLine [LineChunk "(Just (0,'a'),Just (2,'b'))"]]+ DocTest.printPrefix "Numeric.Interpolation.NodeList:98: "+{-# LINE 98 "src/Numeric/Interpolation/NodeList.hs" #-}+ DocTest.example+{-# LINE 98 "src/Numeric/Interpolation/NodeList.hs" #-}+ (Nodes.lookup (Nodes.fromList ([(0,'a'),(2::Int,'b')])) 2)+ [ExpectedLine [LineChunk "(Just (2,'b'),Nothing)"]]+ DocTest.printPrefix "Numeric.Interpolation.NodeList:100: "+{-# LINE 100 "src/Numeric/Interpolation/NodeList.hs" #-}+ DocTest.example+{-# LINE 100 "src/Numeric/Interpolation/NodeList.hs" #-}+ (Nodes.lookup (Nodes.fromList ([(0,'a'),(2::Int,'b')])) 3)+ [ExpectedLine [LineChunk "(Just (2,'b'),Nothing)"]]+ DocTest.printPrefix "Numeric.Interpolation.NodeList:102: "+{-# LINE 102 "src/Numeric/Interpolation/NodeList.hs" #-}+ DocTest.example+{-# LINE 102 "src/Numeric/Interpolation/NodeList.hs" #-}+ (Nodes.lookup (Nodes.fromList ([(0,'a'),(2,'b'),(5::Int,'c')])) 3)+ [ExpectedLine [LineChunk "(Just (2,'b'),Just (5,'c'))"]]
+ test/Test/Numeric/Interpolation/Piece.hs view
@@ -0,0 +1,43 @@+-- Do not edit! Automatically created with doctest-extract from src/Numeric/Interpolation/Piece.hs+{-# LINE 10 "src/Numeric/Interpolation/Piece.hs" #-}++module Test.Numeric.Interpolation.Piece where++import qualified Test.DocTest.Driver as DocTest++{-# LINE 11 "src/Numeric/Interpolation/Piece.hs" #-}+import qualified Numeric.Interpolation.Piece as Piece+import qualified Numeric.Interpolation.Private.Piece as PiecePriv+import qualified Test.QuickCheck as QC+import Test.QuickCheck ((==>))++forAllDistinctPoints ::+ (Show a, QC.Arbitrary a, QC.Testable prop) =>+ ((Rational, a) -> (Rational, a) -> prop) -> QC.Property+forAllDistinctPoints f =+ QC.forAll QC.arbitrary $ \p1@(x1,_) ->+ QC.forAll QC.arbitrary $ \p2@(x2,_) ->+ x1/=x2 ==> f p1 p2++test :: DocTest.T ()+test = do+ DocTest.printPrefix "Numeric.Interpolation.Piece:26: "+{-# LINE 26 "src/Numeric/Interpolation/Piece.hs" #-}+ DocTest.property+{-# LINE 26 "src/Numeric/Interpolation/Piece.hs" #-}+ (forAllDistinctPoints $ \p1 p2 x -> Piece.linear p1 p2 x == Piece.linear p2 p1 x)+ DocTest.printPrefix "Numeric.Interpolation.Piece:35: "+{-# LINE 35 "src/Numeric/Interpolation/Piece.hs" #-}+ DocTest.property+{-# LINE 35 "src/Numeric/Interpolation/Piece.hs" #-}+ (forAllDistinctPoints $ \p1 p2 x -> Piece.hermite1 p1 p2 x == Piece.hermite1 p2 p1 x)+ DocTest.printPrefix "Numeric.Interpolation.Piece:36: "+{-# LINE 36 "src/Numeric/Interpolation/Piece.hs" #-}+ DocTest.property+{-# LINE 36 "src/Numeric/Interpolation/Piece.hs" #-}+ (forAllDistinctPoints $ \p1@(x1,y1) p2@(x2,y2) x -> Piece.linear p1 p2 x == let slope = (y2-y1)/(x2-x1) in Piece.hermite1 (x1, (y1,slope)) (x2, (y2,slope)) x)+ DocTest.printPrefix "Numeric.Interpolation.Piece:37: "+{-# LINE 37 "src/Numeric/Interpolation/Piece.hs" #-}+ DocTest.property+{-# LINE 37 "src/Numeric/Interpolation/Piece.hs" #-}+ (forAllDistinctPoints $ \p1 p2 x -> Piece.hermite1 p1 p2 x == PiecePriv.hermite1 p1 p2 x)
+ test/Test/Numeric/Interpolation/Piecewise.hs view
@@ -0,0 +1,119 @@+-- Do not edit! Automatically created with doctest-extract from src/Numeric/Interpolation/Piecewise.hs+{-# LINE 10 "src/Numeric/Interpolation/Piecewise.hs" #-}++module Test.Numeric.Interpolation.Piecewise where++import Test.DocTest.Base+import qualified Test.DocTest.Driver as DocTest++{-# LINE 11 "src/Numeric/Interpolation/Piecewise.hs" #-}+import qualified Numeric.Interpolation.Piecewise as Piecewise+import qualified Numeric.Interpolation.NodeList as Nodes+import qualified Numeric.Interpolation.Type as Type++import qualified Data.List as List+import qualified Data.Set as Set+import Data.Array (accumArray, listArray)+import Data.List.HT (lengthAtLeast)++import qualified Test.QuickCheck as QC+import Test.QuickCheck ((==>))++forAllSortedRatios ::+ (QC.Testable prop) => ([Rational] -> Rational -> prop) -> QC.Property+forAllSortedRatios f =+ QC.forAll (fmap Set.toAscList QC.arbitrary) $ \nodeXs x ->+ f (map fromInteger nodeXs) (fromInteger x)++checkEq ::+ (Ord x, Eq y, Num y) =>+ Type.T x y ny -> [x] -> x -> Bool+checkEq typ nodeXs x =+ let ys =+ map+ (flip (Piecewise.interpolateConstantExt typ) x)+ (Type.basisFunctions typ nodeXs)+ bounds = (0, length ys - 1)+ in listArray bounds ys+ ==+ accumArray (flip const) 0 bounds+ (Type.sampleBasisFunctions typ nodeXs x)++quantile :: (Show a, Ord a, Fractional a) => [a] -> a -> a+quantile [] _ = error "quantile: empty list"+quantile [y] _ = y+quantile ys x =+ let len = fromIntegral (length ys - 1)+ in Piecewise.interpolateConstantExt Type.linear+ (Nodes.fromList $ zip (map (/ len) $ map fromInteger [0..]) $+ List.sort ys)+ x++test :: DocTest.T ()+test = do+ DocTest.printPrefix "Numeric.Interpolation.Piecewise:58: "+{-# LINE 58 "src/Numeric/Interpolation/Piecewise.hs" #-}+ DocTest.example+{-# LINE 58 "src/Numeric/Interpolation/Piecewise.hs" #-}+ (Piecewise.interpolate Type.linear (Nodes.fromList [(0,0),(3,6),(5,10::Rational)]) 2)+ [ExpectedLine [LineChunk "4 % 1"]]+ DocTest.printPrefix "Numeric.Interpolation.Piecewise:60: "+{-# LINE 60 "src/Numeric/Interpolation/Piecewise.hs" #-}+ DocTest.example+{-# LINE 60 "src/Numeric/Interpolation/Piecewise.hs" #-}+ (Piecewise.interpolate Type.hermite1 (Nodes.fromList [(0,(0,0)),(3,(9,6)),(5,(25,10::Rational))]) 2)+ [ExpectedLine [LineChunk "4 % 1"]]+ DocTest.printPrefix "Numeric.Interpolation.Piecewise:62: "+{-# LINE 62 "src/Numeric/Interpolation/Piecewise.hs" #-}+ DocTest.example+{-# LINE 62 "src/Numeric/Interpolation/Piecewise.hs" #-}+ (Piecewise.interpolate Type.hermite1 (Nodes.fromList [(0,(1,-2)),(3,(4,4)),(5,(16,8::Rational))]) 2)+ [ExpectedLine [LineChunk "1 % 1"]]+ DocTest.printPrefix "Numeric.Interpolation.Piecewise:75: "+{-# LINE 75 "src/Numeric/Interpolation/Piecewise.hs" #-}+ DocTest.property+{-# LINE 75 "src/Numeric/Interpolation/Piecewise.hs" #-}+ (forAllSortedRatios $ checkEq Type.linear)+ DocTest.printPrefix "Numeric.Interpolation.Piecewise:76: "+{-# LINE 76 "src/Numeric/Interpolation/Piecewise.hs" #-}+ DocTest.property+{-# LINE 76 "src/Numeric/Interpolation/Piecewise.hs" #-}+ (forAllSortedRatios $ checkEq Type.hermite1)+ DocTest.printPrefix "Numeric.Interpolation.Piecewise:77: "+{-# LINE 77 "src/Numeric/Interpolation/Piecewise.hs" #-}+ DocTest.property+{-# LINE 77 "src/Numeric/Interpolation/Piecewise.hs" #-}+ (forAllSortedRatios $ \nodeXs x -> lengthAtLeast 4 nodeXs ==> checkEq Type.cubicLinear nodeXs x)+ DocTest.printPrefix "Numeric.Interpolation.Piecewise:78: "+{-# LINE 78 "src/Numeric/Interpolation/Piecewise.hs" #-}+ DocTest.property+{-# LINE 78 "src/Numeric/Interpolation/Piecewise.hs" #-}+ (forAllSortedRatios $ \nodeXs x -> lengthAtLeast 4 nodeXs ==> checkEq Type.cubicParabola nodeXs x)+ DocTest.printPrefix "Numeric.Interpolation.Piecewise:91: "+{-# LINE 91 "src/Numeric/Interpolation/Piecewise.hs" #-}+ DocTest.property+{-# LINE 91 "src/Numeric/Interpolation/Piecewise.hs" #-}+ (\(QC.NonEmpty xs) -> quantile (xs::[Rational]) 0 == minimum xs)+ DocTest.printPrefix "Numeric.Interpolation.Piecewise:92: "+{-# LINE 92 "src/Numeric/Interpolation/Piecewise.hs" #-}+ DocTest.property+{-# LINE 92 "src/Numeric/Interpolation/Piecewise.hs" #-}+ (\(QC.NonEmpty xs) -> quantile (xs::[Rational]) 1 == maximum xs)+ DocTest.printPrefix "Numeric.Interpolation.Piecewise:84: "+{-# LINE 84 "src/Numeric/Interpolation/Piecewise.hs" #-}+ DocTest.example+{-# LINE 84 "src/Numeric/Interpolation/Piecewise.hs" #-}+ (quantile [2,5,3::Rational] 0.5)+ [ExpectedLine [LineChunk "3 % 1"]]+ DocTest.printPrefix "Numeric.Interpolation.Piecewise:86: "+{-# LINE 86 "src/Numeric/Interpolation/Piecewise.hs" #-}+ DocTest.example+{-# LINE 86 "src/Numeric/Interpolation/Piecewise.hs" #-}+ (quantile [2,5,3,7::Rational] 0.5)+ [ExpectedLine [LineChunk "4 % 1"]]+ DocTest.printPrefix "Numeric.Interpolation.Piecewise:88: "+{-# LINE 88 "src/Numeric/Interpolation/Piecewise.hs" #-}+ DocTest.example+{-# LINE 88 "src/Numeric/Interpolation/Piecewise.hs" #-}+ (quantile [2,5,3,7::Rational] 0.25)+ [ExpectedLine [LineChunk "11 % 4"]]
+ test/Test/Numeric/Interpolation/Type.hs view
@@ -0,0 +1,42 @@+-- Do not edit! Automatically created with doctest-extract from src/Numeric/Interpolation/Type.hs+{-# LINE 16 "src/Numeric/Interpolation/Type.hs" #-}++module Test.Numeric.Interpolation.Type where++import qualified Test.DocTest.Driver as DocTest++{-# LINE 17 "src/Numeric/Interpolation/Type.hs" #-}+import qualified Numeric.Interpolation.Type as Type++checkOverlap :: Type.T Double y ny -> [Double] -> Double -> Bool+checkOverlap typ xs xi =+ let samples = map fst $ Type.sampleBasisFunctions typ xs xi+ in all (< minimum samples + Type.basisOverlap typ) samples++checkOverlapNotTotal :: Type.T Double y ny -> [Double] -> Double -> Bool+checkOverlapNotTotal typ xs xi =+ let samples = map fst $ Type.sampleBasisFunctions typ xs xi+ in maximum samples - minimum samples < Type.basisOverlap typ++test :: DocTest.T ()+test = do+ DocTest.printPrefix "Numeric.Interpolation.Type:46: "+{-# LINE 46 "src/Numeric/Interpolation/Type.hs" #-}+ DocTest.property+{-# LINE 46 "src/Numeric/Interpolation/Type.hs" #-}+ (checkOverlap Type.linear)+ DocTest.printPrefix "Numeric.Interpolation.Type:62: "+{-# LINE 62 "src/Numeric/Interpolation/Type.hs" #-}+ DocTest.property+{-# LINE 62 "src/Numeric/Interpolation/Type.hs" #-}+ (checkOverlap Type.hermite1)+ DocTest.printPrefix "Numeric.Interpolation.Type:81: "+{-# LINE 81 "src/Numeric/Interpolation/Type.hs" #-}+ DocTest.property+{-# LINE 81 "src/Numeric/Interpolation/Type.hs" #-}+ (checkOverlap Type.cubicLinear)+ DocTest.printPrefix "Numeric.Interpolation.Type:97: "+{-# LINE 97 "src/Numeric/Interpolation/Type.hs" #-}+ DocTest.property+{-# LINE 97 "src/Numeric/Interpolation/Type.hs" #-}+ (checkOverlap Type.cubicParabola)
− test/Test/Overlap.hs
@@ -1,25 +0,0 @@-module Test.Overlap where--import qualified Numeric.Interpolation.Type as Type--import Test.QuickCheck (quickCheck, )----test :: Type.T Double y ny -> IO ()-test typ =- quickCheck $ \xs xi ->- let samples = map fst $ Type.sampleBasisFunctions typ xs xi- {- not total:- maximum samples - minimum samples < Type.basisOverlap typ- -}- in all (< minimum samples + Type.basisOverlap typ) samples---tests :: [(String, IO ())]-tests =- ("linear", test Type.linear) :- ("hermite1", test Type.hermite1) :- ("cubicLinear", test Type.cubicLinear) :- ("cubicParabola", test Type.cubicParabola) :- []
− test/Test/Piece.hs
@@ -1,60 +0,0 @@-module Test.Piece where--import qualified Numeric.Interpolation.Piece as Piece-import qualified Numeric.Interpolation.Private.Piece as PiecePriv--import Test.QuickCheck (Property, quickCheck, (==>), )---type Point = (Rational, Rational)--linearCommutative ::- Point -> Point -> Rational -> Property-linearCommutative p1@(x1,_) p2@(x2,_) x =- x1/=x2- ==>- Piece.linear p1 p2 x- ==- Piece.linear p2 p1 x---type PointSlope = (Rational, (Rational, Rational))--hermite1Commutative ::- PointSlope -> PointSlope -> Rational -> Property-hermite1Commutative p1@(x1,_) p2@(x2,_) x =- x1/=x2- ==>- Piece.hermite1 p1 p2 x- ==- Piece.hermite1 p2 p1 x---linearHermite1 ::- Point -> Point -> Rational -> Property-linearHermite1 p1@(x1,y1) p2@(x2,y2) x =- x1/=x2- ==>- Piece.linear p1 p2 x- ==- let slope = (y2-y1)/(x2-x1)- in Piece.hermite1 (x1, (y1,slope)) (x2, (y2, slope)) x---hermite1Alternative ::- PointSlope -> PointSlope -> Rational -> Property-hermite1Alternative p1@(x1,_) p2@(x2,_) x =- x1/=x2- ==>- Piece.hermite1 p1 p2 x- ==- PiecePriv.hermite1 p1 p2 x---tests :: [(String, IO ())]-tests =- ("linearCommutative", quickCheck linearCommutative) :- ("hermite1Commutative", quickCheck hermite1Commutative) :- ("linearHermite1", quickCheck linearHermite1) :- ("hermite1Alternative", quickCheck hermite1Alternative) :- []
− test/Test/Sample.hs
@@ -1,62 +0,0 @@-module Test.Sample where--import qualified Numeric.Interpolation.Type as Type-import qualified Numeric.Interpolation.Piecewise as Piecewise--import qualified Data.Set as Set-import Data.Array (accumArray, listArray, )-import Data.List.HT (lengthAtLeast, )--import Test.QuickCheck (Property, quickCheck, (==>), )----withSortedRatios ::- ([Rational] -> Rational -> a) ->- ([Integer] -> Integer -> a)-withSortedRatios f nodeXs x =- f (map fromInteger $ Set.toAscList $ Set.fromList nodeXs) (fromInteger x)--checkEq ::- (Ord x, Eq y, Num y) =>- Type.T x y ny -> [x] -> x -> Bool-checkEq typ nodeXs x =- let ys =- map- (flip (Piecewise.interpolateConstantExt typ) x)- (Type.basisFunctions typ nodeXs)- bounds = (0, length ys - 1)- in listArray bounds ys- ==- accumArray (flip const) 0 bounds- (Type.sampleBasisFunctions typ nodeXs x)---linear :: [Integer] -> Integer -> Bool-linear = withSortedRatios $ checkEq Type.linear--hermite1 :: [Integer] -> Integer -> Bool-hermite1 = withSortedRatios $ checkEq Type.hermite1---derivativeFree ::- Type.T Rational Rational ny ->- [Integer] -> Integer -> Property-derivativeFree typ =- withSortedRatios $ \nodeXs x ->- lengthAtLeast 4 nodeXs ==> checkEq typ nodeXs x--cubicLinear :: [Integer] -> Integer -> Property-cubicLinear = derivativeFree Type.cubicLinear--cubicParabola :: [Integer] -> Integer -> Property-cubicParabola = derivativeFree Type.cubicParabola---tests :: [(String, IO ())]-tests =- ("linear", quickCheck linear) :- ("hermite1", quickCheck hermite1) :- ("cubicLinear", quickCheck cubicLinear) :- ("cubicParabola", quickCheck cubicParabola) :- []