module AERN2.MP.Accuracy
(Accuracy(NoInformation, Exact), bits, fromAccuracy,
HasAccuracy(..),
HasAccuracyGuide(..), CanSetAccuracyGuide(..), adjustAccuracyGuide,
getFiniteAccuracy,
ac2prec,
CanReduceSizeUsingAccuracyGuide(..),
specCanReduceSizeUsingAccuracyGuide,
iterateUntilAccurate,
convergentList2CauchySeq,
seqByPrecision2CauchySeq,
setPrecisionAtLeastAccuracy,
HasApproximate(..))
where
import MixedTypesNumPrelude
import qualified Prelude as P
import Control.CollectErrors
import Data.Complex
import Test.Hspec
import Test.QuickCheck
import AERN2.Norm
import AERN2.MP.Precision
_example1 :: Accuracy
_example1 = 1 + 2*(bits 100)
data Accuracy = NoInformation | Bits { fromAccuracy :: Integer } | Exact
deriving (P.Eq, P.Ord)
instance Arbitrary Accuracy where
arbitrary =
frequency
[(int 1, pure Exact),
(int 1, pure NoInformation),
(int 8, Bits <$> arbitrary)]
instance Enum Accuracy where
fromEnum NoInformation = minBound
fromEnum (Bits i) = int i
fromEnum Exact = maxBound
toEnum i = Bits (integer i)
instance Bounded Accuracy where
minBound = NoInformation
maxBound = Exact
instance ConvertibleExactly Integer Accuracy where
safeConvertExactly = Right . Bits
instance ConvertibleExactly Int Accuracy where
safeConvertExactly = Right . Bits . integer
instance ConvertibleExactly Precision Accuracy where
safeConvertExactly = Right . Bits . integer
instance ConvertibleExactly NormLog Accuracy where
safeConvertExactly (NormBits b) = Right $ bits (b)
safeConvertExactly NormZero = Right Exact
bits :: (ConvertibleExactly t Accuracy) => t -> Accuracy
bits = convertExactly
instance Show Accuracy where
show (NoInformation) = "NoInformation"
show (Bits a) = "bits " ++ show a
show (Exact) = "Exact"
instance HasEqAsymmetric Accuracy Accuracy
instance HasOrderAsymmetric Accuracy Accuracy
instance CanMinMaxAsymmetric Accuracy Accuracy
instance HasEqAsymmetric Accuracy Integer where
equalTo = convertSecond equalTo
instance HasEqAsymmetric Integer Accuracy where
equalTo = convertFirst equalTo
instance HasEqAsymmetric Accuracy Int where
equalTo = convertSecond equalTo
instance HasEqAsymmetric Int Accuracy where
equalTo = convertFirst equalTo
instance HasOrderAsymmetric Accuracy Integer where
lessThan = convertSecond lessThan
leq = convertSecond leq
instance HasOrderAsymmetric Integer Accuracy where
lessThan = convertFirst lessThan
leq = convertFirst leq
instance HasOrderAsymmetric Accuracy Int where
lessThan = convertSecond lessThan
leq = convertSecond leq
instance HasOrderAsymmetric Int Accuracy where
lessThan = convertFirst lessThan
leq = convertFirst leq
instance CanMinMaxAsymmetric Accuracy Integer where
type MinMaxType Accuracy Integer = Accuracy
min = convertSecond min
max = convertSecond max
instance CanMinMaxAsymmetric Integer Accuracy where
type MinMaxType Integer Accuracy = Accuracy
min = convertFirst min
max = convertFirst max
instance CanMinMaxAsymmetric Accuracy Int where
type MinMaxType Accuracy Int = Accuracy
min = convertSecond min
max = convertSecond max
instance CanMinMaxAsymmetric Int Accuracy where
type MinMaxType Int Accuracy = Accuracy
min = convertFirst min
max = convertFirst max
instance CanNeg Accuracy where
negate NoInformation = Exact
negate Exact = NoInformation
negate (Bits a) = Bits (a)
instance CanAddAsymmetric Accuracy Accuracy where
add NoInformation _ = NoInformation
add _ NoInformation = NoInformation
add (Bits a) (Bits b) = Bits $ a + b
add Exact _ = Exact
add _ Exact = Exact
instance CanSub Accuracy Accuracy
instance CanMulAsymmetric Accuracy Integer where
type MulType Accuracy Integer = Accuracy
mul NoInformation _ = NoInformation
mul (Bits a) i = Bits $ a * i
mul Exact _ = Exact
instance CanMulAsymmetric Integer Accuracy where
type MulType Integer Accuracy = Accuracy
mul i a = mul a i
instance CanAddAsymmetric Accuracy Integer where
type AddType Accuracy Integer = Accuracy
add NoInformation _ = NoInformation
add (Bits a) i = Bits $ a + i
add Exact _ = Exact
instance CanAddAsymmetric Integer Accuracy where
type AddType Integer Accuracy = Accuracy
add i a = add a i
instance CanSub Accuracy Integer where
type SubType Accuracy Integer = Accuracy
sub NoInformation _ = NoInformation
sub (Bits a) i = Bits $ a i
sub Exact _ = Exact
class HasAccuracy a where
getAccuracy :: a -> Accuracy
instance (HasAccuracy a, SuitableForCE es) => HasAccuracy (CollectErrors es a) where
getAccuracy (CollectErrors ma es) =
case ma of
Just a | not (hasCertainError es) -> getAccuracy a
_ -> NoInformation
instance HasAccuracy Int where getAccuracy _ = Exact
instance HasAccuracy Integer where getAccuracy _ = Exact
instance HasAccuracy Rational where getAccuracy _ = Exact
instance HasAccuracy Bool where getAccuracy _ = Exact
instance HasAccuracy t => HasAccuracy (Complex t) where
getAccuracy (a :+ i) =
(getAccuracy a) `min` (getAccuracy i)
instance HasAccuracy t => HasAccuracy [t] where
getAccuracy xs = foldl min Exact $ map getAccuracy xs
instance HasAccuracy t => HasAccuracy (Maybe t) where
getAccuracy (Just x) = getAccuracy x
getAccuracy _ = NoInformation
class HasAccuracyGuide a where
getAccuracyGuide :: a -> Accuracy
class HasAccuracyGuide a => CanSetAccuracyGuide a where
setAccuracyGuide :: Accuracy -> a -> a
adjustAccuracyGuide ::
(CanSetAccuracyGuide a) =>
(Accuracy -> Accuracy) -> a -> a
adjustAccuracyGuide adj_acG a =
setAccuracyGuide (adj_acG (getAccuracyGuide a)) a
getFiniteAccuracy ::
(HasAccuracy t, HasPrecision t) =>
t -> Accuracy
getFiniteAccuracy b =
case getAccuracy b of
Exact -> bits $ getPrecision b
a -> a
iterateUntilAccurate ::
(HasAccuracy t) =>
Accuracy ->
(Precision -> Maybe t) ->
[(Precision, Maybe t)]
iterateUntilAccurate ac =
iterateUntilOK (ac2prec ac) $ \maybeResult ->
case maybeResult of
Just result -> getAccuracy result >= ac
_ -> False
ac2prec :: Accuracy -> Precision
ac2prec ac =
case ac of
Bits b -> prec (max 2 $ b + 50)
_ -> prec 100
seqByPrecision2CauchySeq ::
(HasAccuracy t) =>
(Precision -> t) -> (Accuracy -> t)
seqByPrecision2CauchySeq seqByPrecision ac =
convergentList2CauchySeq list ac
where
list =
map seqByPrecision $ dropWhile (lowPrec ac) (standardPrecisions (ac2prec ac))
lowPrec Exact _ = False
lowPrec _ p = bits p < ac
convergentList2CauchySeq :: (HasAccuracy t) => [t] -> (Accuracy -> t)
convergentList2CauchySeq list ac = findAccurate list
where
findAccurate [] =
error "convergentList2CauchySeq: the sequence either converges too slowly or it does not converge"
findAccurate (b : rest)
| getAccuracy b >= ac = b
| otherwise = findAccurate rest
setPrecisionAtLeastAccuracy :: (CanSetPrecision t) => Accuracy -> t -> t
setPrecisionAtLeastAccuracy acc b
| p_b < p_acc = setPrecision p_acc b
| otherwise = b
where
p_acc =
case acc of
Exact -> error $ "setPrecisionAtLeastAccuracy: cannot match Exact accuracy"
NoInformation -> p_b
_ -> prec $ max 2 (fromAccuracy acc)
p_b = getPrecision b
class CanReduceSizeUsingAccuracyGuide t where
reduceSizeUsingAccuracyGuide :: Accuracy -> t -> t
specCanReduceSizeUsingAccuracyGuide ::
( CanReduceSizeUsingAccuracyGuide t
, HasEqCertainly t t
, Arbitrary t, Show t)
=>
(T t) -> Spec
specCanReduceSizeUsingAccuracyGuide (T tName :: T t) =
describe ("CanReduceSizeUsingAccuracyGuide " ++ tName) $ do
it "is safe" $
property $
\ (t :: t) (ac :: Accuracy) ->
reduceSizeUsingAccuracyGuide ac t ?==? t
class HasApproximate t where
type Approximate t
getApproximate :: Accuracy -> t -> (Approximate t)