{-# LANGUAGE Strict #-}
module Data.Approx
(
Approx (..)
, inRange, safeInRange, inTol
) where
import Data.List (foldl')
import qualified Data.Vector.Unboxed as U
import qualified Data.Vector.Unboxed.Mutable as M
import qualified Data.Vector as V
import Data.Time (Day, UTCTime)
import Data.Time.Clock (diffUTCTime)
import qualified Data.HashMap.Strict as Hm
import Data.Hashable
import Data.Text (Text)
import qualified Data.Complex as Cx
import Data.Complex (Complex ( (:+) ) )
eZerD :: Double
eZerD :: Double
eZerD = Double
1e-8; {-# INLINE eZerD #-}
eEqD :: Double
eEqD :: Double
eEqD = Double
1e-7; {-# INLINE eEqD #-}
eZerF :: Float
eZerF :: Float
eZerF = Float
1e-6; {-# INLINE eZerF #-}
eEqF :: Float
eEqF :: Float
eEqF = Float
1e-5; {-# INLINE eEqF #-}
infix 4 =~, /~
class Approx a where
(=~), (/~) :: a -> a -> Bool
(=~) a
x a
y = Bool -> Bool
not (a
x a -> a -> Bool
forall a. Approx a => a -> a -> Bool
/~ a
y)
{-# INLINE (=~) #-}
(/~) a
x a
y = Bool -> Bool
not (a
x a -> a -> Bool
forall a. Approx a => a -> a -> Bool
=~ a
y)
{-# INLINE (/~) #-}
{-# MINIMAL (=~) | (/~) #-}
instance Approx Day where Day
x =~ :: Day -> Day -> Bool
=~ Day
y = Day
x Day -> Day -> Bool
forall a. Eq a => a -> a -> Bool
== Day
y; {-# INLINE (=~) #-}
instance Approx Char where Char
x =~ :: Char -> Char -> Bool
=~ Char
y = Char
x Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
y; {-# INLINE (=~) #-}
instance Approx Bool where Bool
x =~ :: Bool -> Bool -> Bool
=~ Bool
y = Bool
x Bool -> Bool -> Bool
forall a. Eq a => a -> a -> Bool
== Bool
y; {-# INLINE (=~) #-}
instance Approx Text where Text
x =~ :: Text -> Text -> Bool
=~ Text
y = Text
x Text -> Text -> Bool
forall a. Eq a => a -> a -> Bool
== Text
y; {-# INLINE (=~) #-}
instance Approx Int where Int
x =~ :: Int -> Int -> Bool
=~ Int
y = Int
x Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
y; {-# INLINE (=~) #-}
instance Approx Integer where Integer
x =~ :: Integer -> Integer -> Bool
=~ Integer
y = Integer
x Integer -> Integer -> Bool
forall a. Eq a => a -> a -> Bool
== Integer
y; {-# INLINE (=~) #-}
instance Approx UTCTime where
UTCTime
x =~ :: UTCTime -> UTCTime -> Bool
=~ UTCTime
y = (Double -> Integer
forall a b. (RealFrac a, Integral b) => a -> b
round (Double -> Integer)
-> (NominalDiffTime -> Double) -> NominalDiffTime -> Integer
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Double -> Double -> Double
forall a. Fractional a => a -> a -> a
/Double
60.0) (Double -> Double)
-> (NominalDiffTime -> Double) -> NominalDiffTime -> Double
forall b c a. (b -> c) -> (a -> b) -> a -> c
. NominalDiffTime -> Double
forall a b. (Real a, Fractional b) => a -> b
realToFrac (NominalDiffTime -> Integer) -> NominalDiffTime -> Integer
forall a b. (a -> b) -> a -> b
$ UTCTime
x UTCTime -> UTCTime -> NominalDiffTime
`diffUTCTime` UTCTime
y) Integer -> Integer -> Bool
forall a. Eq a => a -> a -> Bool
== Integer
0
{-# INLINE (=~) #-}
instance Approx a => Approx (Cx.Complex a) where
(a
a :+ a
b) =~ :: Complex a -> Complex a -> Bool
=~ (a
x :+ a
y) = (a
a a -> a -> Bool
forall a. Approx a => a -> a -> Bool
=~ a
x) Bool -> Bool -> Bool
&& (a
b a -> a -> Bool
forall a. Approx a => a -> a -> Bool
=~ a
y); {-# INLINE (=~) #-}
instance Approx Float where
Float
x =~ :: Float -> Float -> Bool
=~ Float
y = (Float
mx Float -> Float -> Bool
forall a. Ord a => a -> a -> Bool
< Float
eZerF) Bool -> Bool -> Bool
|| Float -> Float
forall a. Num a => a -> a
abs (Float
xFloat -> Float -> Float
forall a. Num a => a -> a -> a
-Float
y) Float -> Float -> Float
forall a. Fractional a => a -> a -> a
/ Float
mx Float -> Float -> Bool
forall a. Ord a => a -> a -> Bool
< Float
eEqF where mx :: Float
mx = Float -> Float -> Float
forall a. Ord a => a -> a -> a
max (Float -> Float
forall a. Num a => a -> a
abs Float
x) (Float -> Float
forall a. Num a => a -> a
abs Float
y)
{-# INLINE (=~) #-}
instance Approx Double where
Double
x =~ :: Double -> Double -> Bool
=~ Double
y = (Double
mx Double -> Double -> Bool
forall a. Ord a => a -> a -> Bool
< Double
eZerD) Bool -> Bool -> Bool
|| Double -> Double
forall a. Num a => a -> a
abs (Double
xDouble -> Double -> Double
forall a. Num a => a -> a -> a
-Double
y) Double -> Double -> Double
forall a. Fractional a => a -> a -> a
/ Double
mx Double -> Double -> Bool
forall a. Ord a => a -> a -> Bool
< Double
eEqD where mx :: Double
mx = Double -> Double -> Double
forall a. Ord a => a -> a -> a
max (Double -> Double
forall a. Num a => a -> a
abs Double
x) (Double -> Double
forall a. Num a => a -> a
abs Double
y)
{-# INLINE (=~) #-}
instance Approx a => Approx (Maybe a) where
Maybe a
Nothing =~ :: Maybe a -> Maybe a -> Bool
=~ Maybe a
Nothing = Bool
True
Just a
x =~ Just a
y = a
x a -> a -> Bool
forall a. Approx a => a -> a -> Bool
=~ a
y
Maybe a
_ =~ Maybe a
_ = Bool
False
{-# INLINE (=~) #-}
instance Approx a => Approx [a] where
[a]
x =~ :: [a] -> [a] -> Bool
=~ [a]
y = ([a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [a]
x Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [a]
y) Bool -> Bool -> Bool
&& [Bool] -> Bool
forall (t :: * -> *). Foldable t => t Bool -> Bool
and ((a -> a -> Bool) -> [a] -> [a] -> [Bool]
forall a b c. (a -> b -> c) -> [a] -> [b] -> [c]
zipWith a -> a -> Bool
forall a. Approx a => a -> a -> Bool
(=~) [a]
x [a]
y)
instance (Approx a, Approx b) => Approx (a, b) where
(a
x,b
y) =~ :: (a, b) -> (a, b) -> Bool
=~ (a
a,b
b) =
( (a
x a -> a -> Bool
forall a. Approx a => a -> a -> Bool
=~ a
a)
Bool -> Bool -> Bool
&& (b
y b -> b -> Bool
forall a. Approx a => a -> a -> Bool
=~ b
b)
)
{-# INLINE (=~) #-}
instance (Approx a, Approx b, Approx c) => Approx (a, b, c) where
(a
x,b
y,c
z) =~ :: (a, b, c) -> (a, b, c) -> Bool
=~ (a
a,b
b,c
c) =
( (a
x a -> a -> Bool
forall a. Approx a => a -> a -> Bool
=~ a
a)
Bool -> Bool -> Bool
&& (b
y b -> b -> Bool
forall a. Approx a => a -> a -> Bool
=~ b
b)
Bool -> Bool -> Bool
&& (c
z c -> c -> Bool
forall a. Approx a => a -> a -> Bool
=~ c
c)
)
{-# INLINE (=~) #-}
instance (Approx a,Approx b,Approx c,Approx d) => Approx (a,b,c,d) where
(a
x,b
y,c
z,d
u) =~ :: (a, b, c, d) -> (a, b, c, d) -> Bool
=~ (a
a,b
b,c
c,d
d) =
( (a
x a -> a -> Bool
forall a. Approx a => a -> a -> Bool
=~ a
a)
Bool -> Bool -> Bool
&& (b
y b -> b -> Bool
forall a. Approx a => a -> a -> Bool
=~ b
b)
Bool -> Bool -> Bool
&& (c
z c -> c -> Bool
forall a. Approx a => a -> a -> Bool
=~ c
c)
Bool -> Bool -> Bool
&& (d
u d -> d -> Bool
forall a. Approx a => a -> a -> Bool
=~ d
d)
)
{-# INLINE (=~) #-}
instance (Approx a,Approx b,Approx c,Approx d, Approx e) => Approx (a,b,c,d,e) where
(a
x,b
y,c
z,d
u,e
v) =~ :: (a, b, c, d, e) -> (a, b, c, d, e) -> Bool
=~ (a
a,b
b,c
c,d
d,e
e) =
( (a
x a -> a -> Bool
forall a. Approx a => a -> a -> Bool
=~ a
a)
Bool -> Bool -> Bool
&& (b
y b -> b -> Bool
forall a. Approx a => a -> a -> Bool
=~ b
b)
Bool -> Bool -> Bool
&& (c
z c -> c -> Bool
forall a. Approx a => a -> a -> Bool
=~ c
c)
Bool -> Bool -> Bool
&& (d
u d -> d -> Bool
forall a. Approx a => a -> a -> Bool
=~ d
d)
Bool -> Bool -> Bool
&& (e
v e -> e -> Bool
forall a. Approx a => a -> a -> Bool
=~ e
e)
)
{-# INLINE (=~) #-}
instance (Approx a,Approx b,Approx c,Approx d, Approx e, Approx f) => Approx (a,b,c,d,e,f) where
(a
x,b
y,c
z,d
u,e
v,f
w) =~ :: (a, b, c, d, e, f) -> (a, b, c, d, e, f) -> Bool
=~ (a
a,b
b,c
c,d
d,e
e,f
f) =
( (a
x a -> a -> Bool
forall a. Approx a => a -> a -> Bool
=~ a
a)
Bool -> Bool -> Bool
&& (b
y b -> b -> Bool
forall a. Approx a => a -> a -> Bool
=~ b
b)
Bool -> Bool -> Bool
&& (c
z c -> c -> Bool
forall a. Approx a => a -> a -> Bool
=~ c
c)
Bool -> Bool -> Bool
&& (d
u d -> d -> Bool
forall a. Approx a => a -> a -> Bool
=~ d
d)
Bool -> Bool -> Bool
&& (e
v e -> e -> Bool
forall a. Approx a => a -> a -> Bool
=~ e
e)
Bool -> Bool -> Bool
&& (f
w f -> f -> Bool
forall a. Approx a => a -> a -> Bool
=~ f
f)
)
{-# INLINE (=~) #-}
instance (Approx a,Approx b,Approx c,Approx d, Approx e, Approx f, Approx g) => Approx (a,b,c,d,e,f,g) where
(a
x,b
y,c
z,d
u,e
v,f
w,g
p) =~ :: (a, b, c, d, e, f, g) -> (a, b, c, d, e, f, g) -> Bool
=~ (a
a,b
b,c
c,d
d,e
e,f
f,g
g) =
( (a
x a -> a -> Bool
forall a. Approx a => a -> a -> Bool
=~ a
a)
Bool -> Bool -> Bool
&& (b
y b -> b -> Bool
forall a. Approx a => a -> a -> Bool
=~ b
b)
Bool -> Bool -> Bool
&& (c
z c -> c -> Bool
forall a. Approx a => a -> a -> Bool
=~ c
c)
Bool -> Bool -> Bool
&& (d
u d -> d -> Bool
forall a. Approx a => a -> a -> Bool
=~ d
d)
Bool -> Bool -> Bool
&& (e
v e -> e -> Bool
forall a. Approx a => a -> a -> Bool
=~ e
e)
Bool -> Bool -> Bool
&& (f
w f -> f -> Bool
forall a. Approx a => a -> a -> Bool
=~ f
f)
Bool -> Bool -> Bool
&& (g
p g -> g -> Bool
forall a. Approx a => a -> a -> Bool
=~ g
g)
)
{-# INLINE (=~) #-}
instance (Approx a,Approx b,Approx c,Approx d, Approx e, Approx f, Approx g, Approx h) => Approx (a,b,c,d,e,f,g,h) where
(a
x,b
y,c
z,d
u,e
v,f
w,g
p,h
q) =~ :: (a, b, c, d, e, f, g, h) -> (a, b, c, d, e, f, g, h) -> Bool
=~ (a
a,b
b,c
c,d
d,e
e,f
f,g
g,h
h) =
( (a
x a -> a -> Bool
forall a. Approx a => a -> a -> Bool
=~ a
a)
Bool -> Bool -> Bool
&& (b
y b -> b -> Bool
forall a. Approx a => a -> a -> Bool
=~ b
b)
Bool -> Bool -> Bool
&& (c
z c -> c -> Bool
forall a. Approx a => a -> a -> Bool
=~ c
c)
Bool -> Bool -> Bool
&& (d
u d -> d -> Bool
forall a. Approx a => a -> a -> Bool
=~ d
d)
Bool -> Bool -> Bool
&& (e
v e -> e -> Bool
forall a. Approx a => a -> a -> Bool
=~ e
e)
Bool -> Bool -> Bool
&& (f
w f -> f -> Bool
forall a. Approx a => a -> a -> Bool
=~ f
f)
Bool -> Bool -> Bool
&& (g
p g -> g -> Bool
forall a. Approx a => a -> a -> Bool
=~ g
g)
Bool -> Bool -> Bool
&& (h
q h -> h -> Bool
forall a. Approx a => a -> a -> Bool
=~ h
h)
)
{-# INLINE (=~) #-}
instance (Approx a,Approx b,Approx c,Approx d, Approx e, Approx f, Approx g, Approx h, Approx i) => Approx (a,b,c,d,e,f,g,h,i) where
(a
x,b
y,c
z,d
u,e
v,f
w,g
p,h
q,i
r) =~ :: (a, b, c, d, e, f, g, h, i) -> (a, b, c, d, e, f, g, h, i) -> Bool
=~ (a
a,b
b,c
c,d
d,e
e,f
f,g
g,h
h,i
i) =
( (a
x a -> a -> Bool
forall a. Approx a => a -> a -> Bool
=~ a
a)
Bool -> Bool -> Bool
&& (b
y b -> b -> Bool
forall a. Approx a => a -> a -> Bool
=~ b
b)
Bool -> Bool -> Bool
&& (c
z c -> c -> Bool
forall a. Approx a => a -> a -> Bool
=~ c
c)
Bool -> Bool -> Bool
&& (d
u d -> d -> Bool
forall a. Approx a => a -> a -> Bool
=~ d
d)
Bool -> Bool -> Bool
&& (e
v e -> e -> Bool
forall a. Approx a => a -> a -> Bool
=~ e
e)
Bool -> Bool -> Bool
&& (f
w f -> f -> Bool
forall a. Approx a => a -> a -> Bool
=~ f
f)
Bool -> Bool -> Bool
&& (g
p g -> g -> Bool
forall a. Approx a => a -> a -> Bool
=~ g
g)
Bool -> Bool -> Bool
&& (h
q h -> h -> Bool
forall a. Approx a => a -> a -> Bool
=~ h
h)
Bool -> Bool -> Bool
&& (i
r i -> i -> Bool
forall a. Approx a => a -> a -> Bool
=~ i
i)
)
{-# INLINE (=~) #-}
instance (Approx a,Approx b,Approx c,Approx d, Approx e, Approx f, Approx g, Approx h, Approx i, Approx j) => Approx (a,b,c,d,e,f,g,h,i,j) where
(a
x,b
y,c
z,d
u,e
v,f
w,g
p,h
q,i
r,j
s) =~ :: (a, b, c, d, e, f, g, h, i, j)
-> (a, b, c, d, e, f, g, h, i, j) -> Bool
=~ (a
a,b
b,c
c,d
d,e
e,f
f,g
g,h
h,i
i,j
j) =
( (a
x a -> a -> Bool
forall a. Approx a => a -> a -> Bool
=~ a
a)
Bool -> Bool -> Bool
&& (b
y b -> b -> Bool
forall a. Approx a => a -> a -> Bool
=~ b
b)
Bool -> Bool -> Bool
&& (c
z c -> c -> Bool
forall a. Approx a => a -> a -> Bool
=~ c
c)
Bool -> Bool -> Bool
&& (d
u d -> d -> Bool
forall a. Approx a => a -> a -> Bool
=~ d
d)
Bool -> Bool -> Bool
&& (e
v e -> e -> Bool
forall a. Approx a => a -> a -> Bool
=~ e
e)
Bool -> Bool -> Bool
&& (f
w f -> f -> Bool
forall a. Approx a => a -> a -> Bool
=~ f
f)
Bool -> Bool -> Bool
&& (g
p g -> g -> Bool
forall a. Approx a => a -> a -> Bool
=~ g
g)
Bool -> Bool -> Bool
&& (h
q h -> h -> Bool
forall a. Approx a => a -> a -> Bool
=~ h
h)
Bool -> Bool -> Bool
&& (i
r i -> i -> Bool
forall a. Approx a => a -> a -> Bool
=~ i
i)
Bool -> Bool -> Bool
&& (j
s j -> j -> Bool
forall a. Approx a => a -> a -> Bool
=~ j
j)
)
{-# INLINE (=~) #-}
instance (Approx a,Approx b,Approx c,Approx d, Approx e, Approx f, Approx g, Approx h, Approx i, Approx j, Approx k) => Approx (a,b,c,d,e,f,g,h,i,j,k) where
(a
x,b
y,c
z,d
u,e
v,f
w,g
p,h
q,i
r,j
s,k
t) =~ :: (a, b, c, d, e, f, g, h, i, j, k)
-> (a, b, c, d, e, f, g, h, i, j, k) -> Bool
=~ (a
a,b
b,c
c,d
d,e
e,f
f,g
g,h
h,i
i,j
j,k
k) =
( (a
x a -> a -> Bool
forall a. Approx a => a -> a -> Bool
=~ a
a)
Bool -> Bool -> Bool
&& (b
y b -> b -> Bool
forall a. Approx a => a -> a -> Bool
=~ b
b)
Bool -> Bool -> Bool
&& (c
z c -> c -> Bool
forall a. Approx a => a -> a -> Bool
=~ c
c)
Bool -> Bool -> Bool
&& (d
u d -> d -> Bool
forall a. Approx a => a -> a -> Bool
=~ d
d)
Bool -> Bool -> Bool
&& (e
v e -> e -> Bool
forall a. Approx a => a -> a -> Bool
=~ e
e)
Bool -> Bool -> Bool
&& (f
w f -> f -> Bool
forall a. Approx a => a -> a -> Bool
=~ f
f)
Bool -> Bool -> Bool
&& (g
p g -> g -> Bool
forall a. Approx a => a -> a -> Bool
=~ g
g)
Bool -> Bool -> Bool
&& (h
q h -> h -> Bool
forall a. Approx a => a -> a -> Bool
=~ h
h)
Bool -> Bool -> Bool
&& (i
r i -> i -> Bool
forall a. Approx a => a -> a -> Bool
=~ i
i)
Bool -> Bool -> Bool
&& (j
s j -> j -> Bool
forall a. Approx a => a -> a -> Bool
=~ j
j)
Bool -> Bool -> Bool
&& (k
t k -> k -> Bool
forall a. Approx a => a -> a -> Bool
=~ k
k)
)
{-# INLINE (=~) #-}
instance (M.Unbox a, Approx a) => Approx (U.Vector a) where
Vector a
x =~ :: Vector a -> Vector a -> Bool
=~ Vector a
y = (Vector a -> Int
forall a. Unbox a => Vector a -> Int
U.length Vector a
x Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Vector a -> Int
forall a. Unbox a => Vector a -> Int
U.length Vector a
y) Bool -> Bool -> Bool
&& Vector Bool -> Bool
U.and ((a -> a -> Bool) -> Vector a -> Vector a -> Vector Bool
forall a b c.
(Unbox a, Unbox b, Unbox c) =>
(a -> b -> c) -> Vector a -> Vector b -> Vector c
U.zipWith a -> a -> Bool
forall a. Approx a => a -> a -> Bool
(=~) Vector a
x Vector a
y)
instance (Approx a) => Approx (V.Vector a) where
Vector a
x =~ :: Vector a -> Vector a -> Bool
=~ Vector a
y = (Vector a -> Int
forall a. Vector a -> Int
V.length Vector a
x Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Vector a -> Int
forall a. Vector a -> Int
V.length Vector a
y) Bool -> Bool -> Bool
&& Vector Bool -> Bool
V.and ((a -> a -> Bool) -> Vector a -> Vector a -> Vector Bool
forall a b c. (a -> b -> c) -> Vector a -> Vector b -> Vector c
V.zipWith a -> a -> Bool
forall a. Approx a => a -> a -> Bool
(=~) Vector a
x Vector a
y)
instance (Eq a, Hashable a, Approx b) => Approx (Hm.HashMap a b) where
HashMap a b
x =~ :: HashMap a b -> HashMap a b -> Bool
=~ HashMap a b
y = HashMap a b -> HashMap a b -> Bool
forall v k.
(Approx v, Eq k, Hashable k) =>
HashMap k v -> HashMap k v -> Bool
fz HashMap a b
x HashMap a b
y Bool -> Bool -> Bool
&& HashMap a b -> HashMap a b -> Bool
forall v k.
(Approx v, Eq k, Hashable k) =>
HashMap k v -> HashMap k v -> Bool
fz HashMap a b
y HashMap a b
x where
fz :: HashMap k v -> HashMap k v -> Bool
fz HashMap k v
p HashMap k v
q = [Bool] -> Bool
forall (t :: * -> *). Foldable t => t Bool -> Bool
and ([Bool] -> Bool) -> [Bool] -> Bool
forall a b. (a -> b) -> a -> b
$ (\(k
k,v
v) -> k -> HashMap k v -> Maybe v
forall k v. (Eq k, Hashable k) => k -> HashMap k v -> Maybe v
Hm.lookup k
k HashMap k v
p Maybe v -> Maybe v -> Bool
forall a. Approx a => a -> a -> Bool
=~ v -> Maybe v
forall a. a -> Maybe a
Just v
v) ((k, v) -> Bool) -> [(k, v)] -> [Bool]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> HashMap k v -> [(k, v)]
forall k v. HashMap k v -> [(k, v)]
Hm.toList HashMap k v
q
infix 4 `inRange`, `safeInRange`, `inTol`
inRange :: Ord a => (a,a) -> a -> Bool
inRange :: (a, a) -> a -> Bool
inRange (a
u,a
v) a
x = (a
u a -> a -> Bool
forall a. Ord a => a -> a -> Bool
<= a
x) Bool -> Bool -> Bool
&& (a
x a -> a -> Bool
forall a. Ord a => a -> a -> Bool
<= a
v)
{-# INLINE inRange #-}
safeInRange :: Ord a => (a,a) -> a -> Bool
safeInRange :: (a, a) -> a -> Bool
safeInRange (a
u,a
v) = (a, a) -> a -> Bool
forall a. Ord a => (a, a) -> a -> Bool
inRange ((a, a) -> a -> Bool) -> (a, a) -> a -> Bool
forall a b. (a -> b) -> a -> b
$ if a
ua -> a -> Bool
forall a. Ord a => a -> a -> Bool
<a
v then (a
u,a
v) else (a
v,a
u)
{-# INLINE safeInRange #-}
inTol :: (Num a, Ord a) => a -> a -> a -> Bool
inTol :: a -> a -> a -> Bool
inTol a
t a
a = (a, a) -> a -> Bool
forall a. Ord a => (a, a) -> a -> Bool
inRange (a
a a -> a -> a
forall a. Num a => a -> a -> a
- a
t, a
a a -> a -> a
forall a. Num a => a -> a -> a
+ a
t)
{-# INLINE inTol #-}