packages feed

aern2-mp-0.2.0.0: src/AERN2/MP/Ball/Limit.hs

{-# LANGUAGE CPP #-}
-- #define DEBUG

{-# OPTIONS_GHC -Wno-orphans #-}
{-|
    Module      :  AERN2.MP.Ball.Limit
    Description :  limits of MPBall sequences
    Copyright   :  (c) Michal Konecny
    License     :  BSD3

    Maintainer  :  mikkonecny@gmail.com
    Stability   :  experimental
    Portability :  portable

    Limits of MPBall sequences.
-}
module AERN2.MP.Ball.Limit where

#ifdef DEBUG
import Debug.Trace (trace)
#define maybeTrace trace
#define maybeTraceIO putStrLn
#else
#define maybeTrace (\ (_ :: String) t -> t)
#define maybeTraceIO (\ (_ :: String) -> return ())
#endif

import MixedTypesNumPrelude

import qualified Numeric.CollectErrors as CN

-- import Math.NumberTheory.Logarithms (integerLog2)

import AERN2.Limit
import AERN2.MP.Ball.Type
import AERN2.MP.Ball.Field ()

{-
  The following strategies are inspired by
  Mueller: The iRRAM: Exact Arithmetic in C++, Section 10.1
  https://link.springer.com/chapter/10.1007/3-540-45335-0_14
-}

instance HasLimits Rational (CN MPBall -> CN MPBall) where
  type LimitType Rational (CN MPBall -> CN MPBall) = (CN MPBall -> CN MPBall)
  limit = limitMPBall (\ac -> 0.5^(fromAccuracy ac))

instance HasLimits Integer (CN MPBall -> CN MPBall) where
  type LimitType Integer (CN MPBall -> CN MPBall) = (CN MPBall -> CN MPBall)
  limit = limitMPBall (\ac -> (fromAccuracy ac))
  -- limit s = limit (s . getN)
  --   where
  --   -- q > 0 => 0 < 0.5^(getN q) <= q
  --   getN :: Rational -> Integer
  --   getN r = integer $ integerLog2 (max 1 $ (ceiling $ 1/r) - 1) + 1

instance HasLimits Int (CN MPBall -> CN MPBall) where
  type LimitType Int (CN MPBall -> CN MPBall) = (CN MPBall -> CN MPBall)
  limit s = limit (s . c)
    where
    c :: Integer -> Int
    c = int

  
limitMPBall :: (Accuracy -> ix) -> (ix -> (CN MPBall -> CN MPBall)) -> (CN MPBall -> CN MPBall)
limitMPBall ac2ix fs x =
  maybeTrace ("limit (CN MPBall -> CN MPBall): x = " ++ show x) $
  maybeTrace ("limit (CN MPBall -> CN MPBall): xPNext = " ++ show xPNext) $
  maybeTrace ("limit (CN MPBall -> CN MPBall): accuracies = " ++ show accuracies) $
  tryAccuracies accuracies
  where
  acX = getFiniteAccuracy x
  accuracies = aux (fromAccuracy acX)
    where
    aux a
      | a >= 4 = bits a : aux ((100 * a) `divI` 105)
      | otherwise = [bits a]
  xPNext = setPrecision (increaseP $ getPrecision x) x
  increaseP p =
    prec $ (integer p) + 10
    -- prec $ ((101 * (integer p)) `div` 100) + 1

  tryAccuracies [] =
    CN.noValueNumErrorPotential $ CN.NumError "limit (CN MPBall -> CN MPBall) failed"
  tryAccuracies (ac : rest) =
    let result = withAccuracy ac in
    case CN.hasError result of
      False -> result
      _ -> tryAccuracies rest

  withAccuracy ac =
    maybeTrace ("limit (CN MPBall -> CN MPBall): withAccuracy: ac = " ++ show ac) $
    (fs ix xPNext) +- e
    where
    ix = ac2ix ac
    e = 0.5^(fromAccuracy ac)

-- data WithLipschitz f = WithLipschitz f f

-- instance HasLimits Rational (WithLipschitz (MPBall -> CN MPBall)) where
--   type LimitType Rational (WithLipschitz (MPBall -> CN MPBall)) = (MPBall -> CN MPBall)
--   limit ffs xPre =
--     maybeTrace ("limit (MPBall -> CN MPBall): x = " ++ show x) $
--     maybeTrace ("limit (MPBall -> CN MPBall): xC = " ++ show xC) $
--     maybeTrace ("limit (MPBall -> CN MPBall): xE = " ++ show xE) $
--     maybeTrace ("limit (MPBall -> CN MPBall): accuracies = " ++ show accuracies) $
--     tryAccuracies accuracies
--     where
--     acX = getFiniteAccuracy x
--     accuracies = aux (fromAccuracy acX)
--       where
--       aux a
--         | a >= 4 = bits a : aux ((100 * a) `divI` 105)
--         | otherwise = [bits a]
--     x = increasePrec xPre
--       where
--       increasePrec z = setPrecision (inc $ getPrecision xPre) z
--       inc p =
--           prec $ (integer p) + 10
--           -- prec $ ((101 * (integer p)) `div` 100) + 1
--     xC = centreAsBall x
--     xE = radius x

--     tryAccuracies [] =
--       noValueNumErrorPotentialECN (Nothing :: Maybe MPBall) $
--         NumError "limit (MPBall -> CN MPBall) failed"
--     tryAccuracies (ac : rest) =
--       let result = withAccuracy ac in
--       case getErrorsCN result of
--         [] -> result
--         _ -> tryAccuracies rest

--     withAccuracy ac =
--       maybeTrace ("limit (MPBall -> CN MPBall): withAccuracy: ac = " ++ show ac) $
--       lift1CE (updateRadius (+ (errorBound e))) fx
--       where
--       e = 0.5^!(fromAccuracy ac)
--       WithLipschitz f f' = ffs e
--       fxC_CN = f xC
--       f'x_CN = f' x
--       fx :: CN MPBall
--       fx =
--           case (ensureNoCN fxC_CN, ensureNoCN f'x_CN) of
--             ((Just fxC, []), (Just f'x, [])) ->
--               cn $ updateRadius (+ (xE * (errorBound f'x))) fxC
--             _ ->
--               f x -- fallback

-- instance HasLimits Rational (WithLipschitz (CReal -> CReal)) where
--   type LimitType Rational (WithLipschitz (CReal -> CReal)) = (CReal -> CReal)
--   limit ffs x = limit fs x
--     where
--     fs e = f
--       where
--       WithLipschitz f _ = ffs e