packages feed

levmar-chart-0.2: example.hs

{-# LANGUAGE ScopedTypeVariables #-}

module Main where

import Control.Monad  (sequence_)
import LevMar.Chart   (PlotValue, levmarChart)
import LevMar.Fitting
import NFunction      (($*))
import System.Random  (Random, mkStdGen, randoms)

import qualified SizedList as SL

-------------------------------------------------------------------------------
-- Some handy type level naturals

type N0 = Z
type N1 = S N0
type N2 = S N1
type N3 = S N2
type N4 = S N3
type N5 = S N4

-------------------------------------------------------------------------------
-- Model functions

constant  :: Num r => SimpleModel N1 r
linear    :: Num r => SimpleModel N2 r
quadratic :: Num r => SimpleModel N3 r
cubic     :: Num r => SimpleModel N4 r

constant        a _ = a
linear        b a x = b * x     + constant      a x
quadratic   c b a x = c * x*x   + linear      b a x
cubic     d c b a x = d * x*x*x + quadratic c b a x

trig  :: Floating r => SimpleModel N2 r
trig a b x = a * cos x + b * sin x

-------------------------------------------------------------------------------
-- Jacobians

constantJacob  :: Num r => SimpleJacobian N1 r
linearJacob    :: Num r => SimpleJacobian N2 r
quadraticJacob :: Num r => SimpleJacobian N3 r
cubicJacob     :: Num r => SimpleJacobian N4 r

constantJacob        _ _ = 1     ::: Nil
linearJacob        _ a x = x     ::: constantJacob      a x
quadraticJacob   _ b a x = x*x   ::: linearJacob      b a x
cubicJacob     _ c b a x = x*x*x ::: quadraticJacob c b a x

trigJacob :: Floating r => SimpleJacobian N2 r
trigJacob _ _ x = cos x ::: sin x ::: Nil

-------------------------------------------------------------------------------
-- Test utility function

testChart :: forall n r a.
             ( Nat n
             , PlotValue r, Fractional r, LevMarable r, Random r
             , PlotValue a, Fractional a
             )
          => (Model n r a)
          -> Maybe (Jacobian n r a)
          -> SizedList n r
          -> [a]
          -> r
          -> IO ()
testChart f j ps xs noise = levmarChart f
                                        j
                                        initPs
                                        samples'
                                        1000
                                        opts
                                        Nothing
                                        Nothing
                                        noLinearConstraints
                                        Nothing
                           >> return ()
    where
      ns         = take (length xs) $ randoms $ mkStdGen rndGenSeed
      initPs     = SL.replicate 0 :: SizedList n r
      samples    = zip xs $ map (f $* ps) xs
      samples'   = zipWith (\(x, y) n -> (x, y + (n - 0.5) * 2 * noise)) samples ns
      rndGenSeed = 123456
      opts       = defaultOpts { optStopNormInfJacTe = 1e-15
                               , optStopNorm2Dp      = 1e-15
                               , optStopNorm2E       = 1e-20
                               }

-------------------------------------------------------------------------------
-- Examples

testConstant :: IO ()
testConstant = testChart constant (Just constantJacob)
                         (42 ::: Nil)
                         [-100 .. 100]
                         (10 :: Double)

testLinear :: IO ()
testLinear = testChart linear (Just linearJacob)
                       (3.14 ::: -8 ::: Nil)
                       [-100 .. 100]
                       (300 :: Double)

testQuadratic :: IO ()
testQuadratic = testChart quadratic (Just quadraticJacob)
                          (0.2 ::: 8 ::: 23 ::: Nil)
                          [-100 .. 100]
                          (1000 :: Double)

testCubic :: IO ()
testCubic = testChart cubic (Just cubicJacob)
                      (-0.05 ::: 0.5 ::: -12 ::: 10 ::: Nil)
                      [-100 .. 100]
                      (8000 :: Double)

testTrig :: IO ()
testTrig = testChart trig (Just trigJacob)
                     (100 ::: 102 ::: Nil)
                     (map (/4) [0..400])
                     (50 :: Double)

-------------------------------------------------------------------------------
-- Main

main :: IO ()
main = sequence_ [ testConstant
                 , testLinear
                 , testQuadratic
                 , testCubic
                 , testTrig
                 ]