module Numeric.GSL.Fitting.Linear (
                                   linear, linear_w, linear_est,
                                   multifit, multifit_w, multifit_est
                             ) where
import Numeric.LinearAlgebra.Data
import Numeric.LinearAlgebra.Devel
import Foreign
import Foreign.C.Types(CInt(..))
import System.IO.Unsafe(unsafePerformIO)
infixl 1 #
a # b = applyRaw a b
linear :: Vector Double    
       -> Vector Double    
       -> (Double,Double,Double,Double,Double,Double) 
linear x y = unsafePerformIO $ do
           alloca $ \c0 ->
               alloca $ \c1 ->
                   alloca $ \chi_sq -> 
                       alloca $ \cov00 -> 
                           alloca $ \cov01 -> 
                               alloca $ \cov11 -> do
                                                  (fitting_linear c0 c1 chi_sq cov00 cov01 cov11) # x # y #| "linear"
                                                  c0' <- peek c0
                                                  c1' <- peek c1
                                                  cov00' <- peek cov00
                                                  cov01' <- peek cov01
                                                  cov11' <- peek cov11
                                                  chi_sq' <- peek chi_sq
                                                  return (c0',c1',cov00',cov01',cov11',chi_sq')
foreign import ccall "fitting-aux.h linear" fitting_linear :: Ptr Double -> Ptr Double -> Ptr Double -> Ptr Double -> Ptr Double -> Ptr Double -> CInt -> Ptr Double -> CInt -> Ptr Double -> IO CInt
linear_w :: Vector Double    
         -> Vector Double    
         -> Vector Double    
         -> (Double,Double,Double,Double,Double,Double) 
linear_w x w y = unsafePerformIO $ do
             alloca $ \c0 ->
                 alloca $ \c1 ->
                     alloca $ \chi_sq ->
                       alloca $ \cov00 -> 
                           alloca $ \cov01 -> 
                               alloca $ \cov11 -> do
                                                  (fitting_linear_w c0 c1 chi_sq cov00 cov01 cov11) # x # w # y #| "linear_w"
                                                  c0' <- peek c0
                                                  c1' <- peek c1
                                                  cov00' <- peek cov00
                                                  cov01' <- peek cov01
                                                  cov11' <- peek cov11
                                                  chi_sq' <- peek chi_sq
                                                  return (c0',c1',cov00',cov01',cov11',chi_sq')
foreign import ccall "fitting-aux.h linear_weighted" fitting_linear_w :: Ptr Double -> Ptr Double -> Ptr Double -> Ptr Double -> Ptr Double -> Ptr Double -> CInt -> Ptr Double -> CInt -> Ptr Double -> CInt -> Ptr Double -> IO CInt
linear_est :: Double          
           -> Double          
           -> Double          
           -> Double          
           -> Double          
           -> Double          
           -> (Double,Double) 
linear_est x c0 c1 cov00 cov01 cov11 = unsafePerformIO $ do
                                       alloca $ \y ->
                                           alloca $ \e -> do
                                               check "linear_est" $ fitting_linear_est x c0 c1 cov00 cov01 cov11 y e
                                               y' <- peek y
                                               e' <- peek e
                                               return (y',e')
foreign import ccall "fitting-aux.h linear_estimate" fitting_linear_est :: Double -> Double -> Double -> Double -> Double -> Double -> Ptr Double -> Ptr Double -> IO CInt
multifit :: Matrix Double          
         -> Vector Double          
         -> (Vector Double,Matrix Double,Double)   
multifit x y = unsafePerformIO $ do
               let p = cols x
               cov <- createMatrix RowMajor p p
               c <- createVector p
               alloca$ \chi_sq -> do
                   (fitting_multifit chi_sq) # (cmat x) # y # c # cov #| "multifit"
                   chi_sq' <- peek chi_sq
                   return (c,cov,chi_sq')
foreign import ccall "fitting_aux.h multifit" fitting_multifit :: Ptr Double -> CInt -> CInt -> Ptr Double -> CInt -> Ptr Double -> CInt -> Ptr Double -> CInt -> CInt -> Ptr Double -> IO CInt
multifit_w :: Matrix Double          
           -> Vector Double          
           -> Vector Double          
           -> (Vector Double,Matrix Double,Double)   
multifit_w x w y = unsafePerformIO $ do
                   let p = cols x
                   cov <- createMatrix RowMajor p p
                   c <- createVector p
                   alloca$ \chi_sq -> do
                       (fitting_multifit_w chi_sq) # (cmat x) # w # y # c # cov #| "multifit"
                       chi_sq' <- peek chi_sq
                       return (c,cov,chi_sq')
foreign import ccall "fitting_aux.h multifit_weighted" fitting_multifit_w :: Ptr Double -> CInt -> CInt -> Ptr Double -> CInt -> Ptr Double -> CInt -> Ptr Double -> CInt -> Ptr Double -> CInt -> CInt -> Ptr Double -> IO CInt
multifit_est :: Vector Double     
             -> Vector Double     
             -> Matrix Double     
             -> (Double,Double)   
multifit_est x c cov = unsafePerformIO $ do
                       alloca $ \y ->
                           alloca $ \e -> do
                               (fitting_multifit_est y e) # x # c # cov #| "multifit_estimate"
                               y' <- peek y
                               e' <- peek e
                               return (y',e')
foreign import ccall "fitting_aux.h multifit_estimate" fitting_multifit_est :: Ptr Double -> Ptr Double -> CInt -> Ptr Double -> CInt -> Ptr Double -> CInt -> CInt -> Ptr Double -> IO CInt