content: 
  -- |
  -- Module     : Simulation.Aivika.Table
  -- Copyright  : Copyright (c) 2009-2017, David Sorokin <david.sorokin@gmail.com>
  -- License    : BSD3
  -- Maintainer : David Sorokin <david.sorokin@gmail.com>
  -- Stability  : experimental
  -- Tested with: GHC 8.0.1
  --
  -- It defines the table functions.
  --
  module Simulation.Aivika.Table
         (tableLookup,
          tableLookupStepwise) where
  
  import Data.Array
  
  -- | Lookup @x@ in a table of pairs @(x, y)@ using linear interpolation.
  tableLookup :: Double -> Array Int (Double, Double) -> Double
  tableLookup x tbl = find first last x
    where
      (first, last) = bounds tbl
      find left right x =
        if left > right then
          error "Incorrect index: tableLookup"
        else
          let index = (left + 1 + right) `div` 2
              x1    = fst $ tbl ! index
          in if x1 <= x then 
               let y | index < right = find index right x
                     | right == last = snd $ tbl ! right
                     | otherwise     = 
                       let x2 = fst $ tbl ! (index + 1)
                           y1 = snd $ tbl ! index
                           y2 = snd $ tbl ! (index + 1)
                       in y1 + (y2 - y1) * (x - x1) / (x2 - x1) 
               in y
             else
               let y | left < index  = find left (index - 1) x
                     | left == first = snd $ tbl ! left
                     | otherwise     = error "Incorrect index: tableLookup"
               in y
  
  -- | Lookup @x@ in a table of pairs @(x, y)@ using stepwise function.
  tableLookupStepwise :: Double -> Array Int (Double, Double) -> Double
  tableLookupStepwise x tbl = find first last x
    where
      (first, last) = bounds tbl
      find left right x =
        if left > right then
          error "Incorrect index: tableLookupStepwise"
        else
          let index = (left + 1 + right) `div` 2
              x1    = fst $ tbl ! index
          in if x1 <= x then 
               let y | index < right = find index right x
                     | right == last = snd $ tbl ! right
                     | otherwise     = snd $ tbl ! right
               in y
             else
               let y | left < index  = find left (index - 1) x
                     | left == first = snd $ tbl ! left
                     | otherwise     = error "Incorrect index: tableLookupStepwise"
               in y
  