{-|
Module      : Approx
Description : Implement Approx for Double, Floats and structures
Copyright   : (c) 2020 Kishaloy Neogi
License     : MIT
Maintainer  : Kishaloy Neogi
Email       : nkishaloy@yahoo.com

The library is created to allow for a easy-to-use reasonable way of emulating approx in Haskell. The codes are all in /pure/ Haskell. The idea is to have a natural mathematical feel in writing code, with operators which just works when working with Double and Float and their composite types like lists, vectors etc. 

The __Approx__ module defines 2 operators __@=~@__ and __@/~@__, which are for checking /nearly equal to/ and /not nearly equal to/ respectively. 

Both the operators __=~__ and __/~__ are put under the class __Approx__. 

At least one of the operators have to be defined and the other gets automatically defined. 

The library already defines the functions for some of the basic / common types. 

For types where __Eq__ is defined like __Char, Bool, Int, Day, Text__ the approx is simply replaced with __==__. 

For __Float__ and __Double__, the following formula is used, 

@
if max ( |x|, |y| ) < epsilon_Zero
then True
else 
  if |x - y| / max ( |x|, |y| ) < epsilon_Eq
  then True
  else False
@

The motivation for defining Approx for classes for which Eq is also defined is to allow for composite types where both Eq and Approx would be present. For example, the following code evaluates to __@True@__, even though the tuple is of type @(Int,Double,Text,[Int],[[Char]],[Double])@.

@
((2,5.35,"happ",[1,2],["ret","we"],[6.78,3.5]) 
    :: (Int,Double,Text,[Int],[[Char]],[Double])) 
    
    =~ (2,5.35,"happ",[1,2],["ret","we"],[6.78,3.5])
@

For UTCTime, the approx operator checks for equality to the nearest minute. The following expression evaluates to __@True@__.

@
(parseTimeM True defaultTimeLocale "%Y-%m-%d %H:%M:%S" "2020-01-15 15:02:15" 
    :: Maybe UTCTime) 

    =~ parseTimeM True defaultTimeLocale "%Y-%m-%d %H:%M:%S" "2020-01-15 15:01:50"
@

The library also provides approx for Complex and common structures like __List, Boxed and Unboxed Vector, Hashmap, Tuples__ and __Maybe__. For all lists, tuples, hashmaps and vectors, the approximation is checked right down to the elements and the order for lists and vectors are important. 

For lists, only finite lists are supported. Any use of infinite lists would cause a runtime error.

There are addtional functions __inRange__, __safeInRange__ and __inTol__, which checks for values within Ranges either /explictily/ defined as in __inRange__ and __safeInRange__ or through tolerances as in __inTol__.

You may see the github repository at <https://github.com/n-kishaloy/approx>

-}

{-# LANGUAGE Strict #-}

module Data.Approx
( 
-- *How to use this library
-- |Add @approx@ to build-depends and @import Data.Approx@

-- *Documentation
  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 =~, /~

-- |The class @Approx@ defines 2 operators __@=~@__ and __@/~@__, which are for checking /nearly equal to/ and /not nearly equal to/ respectively.
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 (u,v) x = check if x is inside the range (u,v)@

Note: The function __assumes @u < v@__. This is done to ensure speed of operations. Use safeInRange, otherwise. 
-}
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 (u,v) x = check if x is inside the range (u,v)@

Note: The function works even if u>v. However, it has addtional checks and is more expensive. Use only if you are not sure that u < v for your use-case.  
-}
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 t p x = inRange (p - t, p + t) x@

The Function checks if __@x@__ is close to __@p@__ within a tolerance band __@t@__. Please ensure __@t@__ is /positive/ or there would be /incorrect/ results.
-}
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 #-}