{-# LANGUAGE BangPatterns, NoImplicitPrelude #-}

module UnitFractionsDecomposition2 where

import GHC.Base
import GHC.Num ((+),(-),(*),abs,Integer)
import GHC.List (null,last,head,length,filter,sum,cycle,zip)
import Data.List (minimumBy,sort)
import GHC.Real (Integral,round,fromIntegral,(/),truncate,ceiling)
import GHC.Float (sqrt)
import Data.Maybe (isNothing,isJust,fromJust,catMaybes)
import Data.Ord (comparing)
import Data.Tuple (fst,snd)

-- | Rounding to thousandth.
threeDigitsK :: Double -> Double
threeDigitsK :: Double -> Double
threeDigitsK Double
k = forall a b. (Integral a, Num b) => a -> b
fromIntegral (forall a b. (RealFrac a, Integral b) => a -> b
round (Double
kforall a. Num a => a -> a -> a
*Double
1000)) forall a. Fractional a => a -> a -> a
/ Double
1000.0
{-# INLINE threeDigitsK #-}

-- | Characterizes the impact of the absolute error sign on the approximation. 
type ErrorImpact = Int

-- | Absolute error with sign for the two unit fractions approximations and the first argument
--  (a in the related paper) being taken as the second parameter for the function. 
--  The second argument here  is expected to be 'fromIntegral' @a0@ where 'Data.List.elem' @a0@ @[2..] == @ 'True'.
absErr2Frac :: Double -> Double -> Double
absErr2Frac :: Double -> Double -> Double
absErr2Frac = ErrorImpact -> Double -> Double -> Double
absErr2FracI ErrorImpact
0
{-# INLINE absErr2Frac #-}

errImpact :: (Integral a) => ErrorImpact -> Double -> a
errImpact :: forall a. Integral a => ErrorImpact -> Double -> a
errImpact ErrorImpact
n = 
  case forall a. Ord a => a -> a -> Ordering
compare ErrorImpact
n ErrorImpact
0 of
    Ordering
GT -> forall a b. (RealFrac a, Integral b) => a -> b
truncate
    Ordering
LT -> forall a b. (RealFrac a, Integral b) => a -> b
ceiling
    Ordering
_ -> forall a b. (RealFrac a, Integral b) => a -> b
round
{-# INLINE errImpact #-}

-- | A generalization of the 'absErr2Frac' with the possibility to check the sign.
absErr2FracI :: ErrorImpact -> Double -> Double -> Double
absErr2FracI :: ErrorImpact -> Double -> Double -> Double
absErr2FracI ErrorImpact
n Double
k Double
y = Double
1.0 forall a. Fractional a => a -> a -> a
/ Double
y forall a. Num a => a -> a -> a
+ Double
1.0 forall a. Fractional a => a -> a -> a
/ forall a b. (Integral a, Num b) => a -> b
fromIntegral ((forall a. Integral a => ErrorImpact -> Double -> a
errImpact ErrorImpact
n) (Double
yforall a. Fractional a => a -> a -> a
/(Double
kforall a. Num a => a -> a -> a
*Double
y forall a. Num a => a -> a -> a
- Double
1.0))) forall a. Num a => a -> a -> a
- Double
k
{-# INLINE absErr2FracI #-}

absErrUDecomp3 :: [Double] -> Double -> Double
absErrUDecomp3 :: [Double] -> Double -> Double
absErrUDecomp3 = ErrorImpact -> [Double] -> Double -> Double
absErrUDecomp3I ErrorImpact
0
{-# INLINE absErrUDecomp3 #-}

absErrUDecomp3I :: ErrorImpact -> [Double] -> Double -> Double
absErrUDecomp3I :: ErrorImpact -> [Double] -> Double -> Double
absErrUDecomp3I ErrorImpact
n [Double
x,Double
y,Double
u] Double
k = Double
1.0 forall a. Fractional a => a -> a -> a
/ Double
x forall a. Num a => a -> a -> a
+ Double
1.0 forall a. Fractional a => a -> a -> a
/ forall a b. (Integral a, Num b) => a -> b
fromIntegral (forall a b. (RealFrac a, Integral b) => a -> b
ceiling Double
y) forall a. Num a => a -> a -> a
+ Double
1.0 forall a. Fractional a => a -> a -> a
/ forall a b. (Integral a, Num b) => a -> b
fromIntegral (forall a. Integral a => ErrorImpact -> Double -> a
errImpact ErrorImpact
n Double
u) forall a. Num a => a -> a -> a
- Double
k
absErrUDecomp3I ErrorImpact
n [Double
x,Double
y] Double
k =  Double
1.0 forall a. Fractional a => a -> a -> a
/ Double
x forall a. Num a => a -> a -> a
+ Double
1.0 forall a. Fractional a => a -> a -> a
/ forall a b. (Integral a, Num b) => a -> b
fromIntegral (forall a. Integral a => ErrorImpact -> Double -> a
errImpact ErrorImpact
n Double
y) forall a. Num a => a -> a -> a
- Double
k
absErrUDecomp3I ErrorImpact
n [Double
x] Double
k = Double
1.0 forall a. Fractional a => a -> a -> a
/ forall a b. (Integral a, Num b) => a -> b
fromIntegral (forall a. Integral a => ErrorImpact -> Double -> a
errImpact ErrorImpact
n Double
x) forall a. Num a => a -> a -> a
- Double
k
absErrUDecomp3I ErrorImpact
_ [Double]
_ Double
_ = -Double
1.0
{-# INLINE absErrUDecomp3I #-}

elemSolution2 :: (Integral a) => Int -> a -> Double -> Bool
elemSolution2 :: forall a. Integral a => ErrorImpact -> a -> Double -> Bool
elemSolution2 ErrorImpact
_ a
_ Double
_ = Bool
True 
{-# INLINE elemSolution2 #-}

elemSolution2I :: (Integral a) => ErrorImpact -> a -> Double -> Bool
elemSolution2I :: forall a. Integral a => ErrorImpact -> a -> Double -> Bool
elemSolution2I ErrorImpact
n a
y Double
k = ErrorImpact
n forall a. Eq a => a -> a -> Bool
== ErrorImpact
0 Bool -> Bool -> Bool
|| (forall a b. (Integral a, Num b) => a -> b
fromIntegral ErrorImpact
n forall a. Num a => a -> a -> a
* ErrorImpact -> Double -> Double -> Double
absErr2FracI ErrorImpact
n Double
k (forall a b. (Integral a, Num b) => a -> b
fromIntegral a
y)) forall a. Ord a => a -> a -> Bool
>= Double
0
{-# INLINE elemSolution2I #-}


{- | Searches for the minimum absolute error solution to two unit fractions decomposition 
 (approximation) for the fraction in the 'isRangeN' 'True' values with taking into account
the sign of the absolute error. 

If the 'ErrorImpact' parameter is equal to 0 , then absolute error can be of any sign,
otherwise the sign of it is the same as the sign of the 'ErrorImpact' argument.
-}
setOfSolutionsGmin :: ErrorImpact -> Double -> (Double, Double)
setOfSolutionsGmin :: ErrorImpact -> Double -> (Double, Double)
setOfSolutionsGmin ErrorImpact
n Double
k 
 | Double -> Bool
isRangeN Double
k = 
    let j0 :: Double
j0 = Double
1.0 forall a. Fractional a => a -> a -> a
/ Double
k
        j :: Integer
j  
          | (forall a b. (Integral a, Num b) => a -> b
fromIntegral forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (RealFrac a, Integral b) => a -> b
ceiling forall a b. (a -> b) -> a -> b
$ Double
j0) forall a. Eq a => a -> a -> Bool
== Double
j0 = forall a b. (RealFrac a, Integral b) => a -> b
ceiling (Double
1.0 forall a. Fractional a => a -> a -> a
/ Double
k) forall a. Num a => a -> a -> a
+ Integer
1
          | Bool
otherwise = forall a b. (RealFrac a, Integral b) => a -> b
ceiling (Double
1.0 forall a. Fractional a => a -> a -> a
/ Double
k)
        p0 :: Double
p0 = Double
2.0forall a. Fractional a => a -> a -> a
/Double
k
        p :: Integer
p 
          | (forall a b. (Integral a, Num b) => a -> b
fromIntegral forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (RealFrac a, Integral b) => a -> b
truncate forall a b. (a -> b) -> a -> b
$ Double
p0) forall a. Eq a => a -> a -> Bool
== Double
p0 = forall a b. (RealFrac a, Integral b) => a -> b
truncate (Double
2.0 forall a. Fractional a => a -> a -> a
/ Double
k) forall a. Num a => a -> a -> a
- Integer
1
          | Bool
otherwise = forall a b. (RealFrac a, Integral b) => a -> b
truncate (Double
2.0forall a. Fractional a => a -> a -> a
/Double
k)
        j1 :: Double
j1 = forall a b. (Integral a, Num b) => a -> b
fromIntegral Integer
j in
            if Integer
j forall a. Eq a => a -> a -> Bool
== Integer
p 
                then if forall a. Integral a => ErrorImpact -> a -> Double -> Bool
elemSolution2I ErrorImpact
n Integer
j Double
k
                         then (Double
j1,Double
j1forall a. Fractional a => a -> a -> a
/(Double
kforall a. Num a => a -> a -> a
*Double
j1 forall a. Num a => a -> a -> a
- Double
1.0)) 
                         else (Double
0, -Double
1.0) 
                else (\Double
t -> if forall a. Num a => a -> a
abs (Double
t forall a. Num a => a -> a -> a
+ Double
0.0001) forall a. Ord a => a -> a -> Bool
< Double
0.000001
                                then (Double
0, Double
0) 
                                else (Double
t, Double
tforall a. Fractional a => a -> a -> a
/(Double
kforall a. Num a => a -> a -> a
*Double
t forall a. Num a => a -> a -> a
- Double
1.0))) forall b c a. (b -> c) -> (a -> b) -> a -> c
. 
                                        forall a b. (a -> b -> b) -> b -> [a] -> b
foldr (\Double
x Double
y -> if forall a. Integral a => ErrorImpact -> a -> Double -> Bool
elemSolution2I ErrorImpact
n (forall a. Integral a => ErrorImpact -> Double -> a
errImpact ErrorImpact
n Double
x) Double
k Bool -> Bool -> Bool
&& forall a. Num a => a -> a
abs (ErrorImpact -> Double -> Double -> Double
absErr2FracI ErrorImpact
n Double
k Double
x) forall a. Ord a => a -> a -> Bool
< forall a. Num a => a -> a
abs (ErrorImpact -> Double -> Double -> Double
absErr2FracI ErrorImpact
n Double
k Double
y) 
                                                           then Double
x 
                                                           else Double
y) (-Double
0.0001) forall a b. (a -> b) -> a -> b
$ [forall a. Ord a => a -> a -> a
min Double
j1 (forall a b. (Integral a, Num b) => a -> b
fromIntegral Integer
p)..forall a. Ord a => a -> a -> a
max Double
j1 (forall a b. (Integral a, Num b) => a -> b
fromIntegral Integer
p)]
 | Bool
otherwise = (Double
0, -Double
1.0)
{-# INLINE setOfSolutionsGmin #-}

{- | A variant of 'setOfSolutionsGmin' where possible 'Integral' values are not equal to the second argument.
-}
setOfSolutionsGmin3 :: (Integral a)  => ErrorImpact -> a -> Double -> (Double, Double)
setOfSolutionsGmin3 :: forall a.
Integral a =>
ErrorImpact -> a -> Double -> (Double, Double)
setOfSolutionsGmin3 ErrorImpact
n a
noteq Double
k 
 | Double -> Bool
isRangeN Double
k = 
    let j0 :: Double
j0 = Double
1.0 forall a. Fractional a => a -> a -> a
/ Double
k
        j :: Integer
j  
          | (forall a b. (Integral a, Num b) => a -> b
fromIntegral forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (RealFrac a, Integral b) => a -> b
ceiling forall a b. (a -> b) -> a -> b
$ Double
j0) forall a. Eq a => a -> a -> Bool
== Double
j0 = forall a b. (RealFrac a, Integral b) => a -> b
ceiling (Double
1.0 forall a. Fractional a => a -> a -> a
/ Double
k) forall a. Num a => a -> a -> a
+ Integer
1
          | Bool
otherwise = forall a b. (RealFrac a, Integral b) => a -> b
ceiling (Double
1.0 forall a. Fractional a => a -> a -> a
/ Double
k)
        p0 :: Double
p0 = Double
2.0forall a. Fractional a => a -> a -> a
/Double
k
        p :: Integer
p 
          | (forall a b. (Integral a, Num b) => a -> b
fromIntegral forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (RealFrac a, Integral b) => a -> b
truncate forall a b. (a -> b) -> a -> b
$ Double
p0) forall a. Eq a => a -> a -> Bool
== Double
p0 = forall a b. (RealFrac a, Integral b) => a -> b
truncate (Double
2.0 forall a. Fractional a => a -> a -> a
/ Double
k) forall a. Num a => a -> a -> a
- Integer
1
          | Bool
otherwise = forall a b. (RealFrac a, Integral b) => a -> b
truncate (Double
2.0forall a. Fractional a => a -> a -> a
/Double
k)
        j1 :: Double
j1 = forall a b. (Integral a, Num b) => a -> b
fromIntegral Integer
j in
            if Integer
j forall a. Eq a => a -> a -> Bool
== Integer
p 
                then if forall a. Integral a => ErrorImpact -> a -> Double -> Bool
elemSolution2I ErrorImpact
n Integer
j Double
k
                         then (Double
j1,Double
j1forall a. Fractional a => a -> a -> a
/(Double
kforall a. Num a => a -> a -> a
*Double
j1 forall a. Num a => a -> a -> a
- Double
1.0)) 
                         else (Double
0, -Double
1.0) 
                else (\Double
t -> if forall a. Num a => a -> a
abs (Double
t forall a. Num a => a -> a -> a
+ Double
0.0001) forall a. Ord a => a -> a -> Bool
< Double
0.000001
                                then (Double
0, Double
0) 
                                else (Double
t, Double
tforall a. Fractional a => a -> a -> a
/(Double
kforall a. Num a => a -> a -> a
*Double
t forall a. Num a => a -> a -> a
- Double
1.0))) forall b c a. (b -> c) -> (a -> b) -> a -> c
. 
                                        forall a b. (a -> b -> b) -> b -> [a] -> b
foldr (\Double
x Double
y -> if forall a. Integral a => ErrorImpact -> a -> Double -> Bool
elemSolution2I ErrorImpact
n (forall a. Integral a => ErrorImpact -> Double -> a
errImpact ErrorImpact
n Double
x) Double
k Bool -> Bool -> Bool
&& forall a. Num a => a -> a
abs (ErrorImpact -> Double -> Double -> Double
absErr2FracI ErrorImpact
n Double
k Double
x) forall a. Ord a => a -> a -> Bool
< forall a. Num a => a -> a
abs (ErrorImpact -> Double -> Double -> Double
absErr2FracI ErrorImpact
n Double
k Double
y) 
                                                           then Double
x 
                                                           else Double
y) (-Double
0.0001) forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. (a -> Bool) -> [a] -> [a]
filter (\Double
ch -> forall a b. (RealFrac a, Integral b) => a -> b
round Double
ch forall a. Eq a => a -> a -> Bool
/= a
noteq) forall a b. (a -> b) -> a -> b
$ [forall a. Ord a => a -> a -> a
min Double
j1 (forall a b. (Integral a, Num b) => a -> b
fromIntegral Integer
p)..forall a. Ord a => a -> a -> a
max Double
j1 (forall a b. (Integral a, Num b) => a -> b
fromIntegral Integer
p)]
 | Bool
otherwise = (Double
0, -Double
1.0)
{-# INLINE setOfSolutionsGmin3 #-}

-- | Searches for the minimum absolute error solution to two unit fractions decomposition 
-- (approximation) for the fraction in @k@ the 'isRangeN' @k = @ 'True'.
suitable2 :: Double -> (Double,Double)
suitable2 :: Double -> (Double, Double)
suitable2 = ErrorImpact -> Double -> (Double, Double)
setOfSolutionsGmin ErrorImpact
0
{-# INLINE suitable2 #-}

{- | Allows to take  into account the sign of the absolute error of the aproximation. If the 
'ErrorImpact' parameter is equal to 0 , then absolute error can be of any sign,
otherwise the sign of it is the same as the sign of the 'ErrorImpact' argument.
-}
suitable21G :: ErrorImpact -> Double -> Maybe ([Double],Double)
suitable21G :: ErrorImpact -> Double -> Maybe ([Double], Double)
suitable21G ErrorImpact
n Double
k = 
   if forall a. Num a => a -> a
abs Double
x forall a. Ord a => a -> a -> Bool
< Double
0.000001 
       then forall a. Maybe a
Nothing 
       else forall a. a -> Maybe a
Just ([Double
x, Double
y], Double
1.0 forall a. Fractional a => a -> a -> a
/ Double
x forall a. Num a => a -> a -> a
+ Double
1.0 forall a. Fractional a => a -> a -> a
/ forall a b. (Integral a, Num b) => a -> b
fromIntegral (forall a. Integral a => ErrorImpact -> Double -> a
errImpact ErrorImpact
n Double
y) forall a. Num a => a -> a -> a
- Double
k) 
      where !(Double
x,Double
y) = ErrorImpact -> Double -> (Double, Double)
setOfSolutionsGmin ErrorImpact
n Double
k
{-# INLINE suitable21G #-}

{- | A variant of 'suitable21G' where possible 'Integral' values are not equal to the second argument.
 -}
suitable21G3 :: (Integral a) => ErrorImpact -> a -> Double -> Maybe ([Double],Double)
suitable21G3 :: forall a.
Integral a =>
ErrorImpact -> a -> Double -> Maybe ([Double], Double)
suitable21G3 ErrorImpact
n a
noteq Double
k = 
   if forall a. Num a => a -> a
abs Double
x forall a. Ord a => a -> a -> Bool
< Double
0.000001 
       then forall a. Maybe a
Nothing 
       else forall a. a -> Maybe a
Just ([Double
x, Double
y], Double
1.0 forall a. Fractional a => a -> a -> a
/ Double
x forall a. Num a => a -> a -> a
+ Double
1.0 forall a. Fractional a => a -> a -> a
/ forall a b. (Integral a, Num b) => a -> b
fromIntegral (forall a. Integral a => ErrorImpact -> Double -> a
errImpact ErrorImpact
n Double
y) forall a. Num a => a -> a -> a
- Double
k) 
      where !(Double
x,Double
y) = forall a.
Integral a =>
ErrorImpact -> a -> Double -> (Double, Double)
setOfSolutionsGmin3 ErrorImpact
n a
noteq Double
k
{-# INLINE suitable21G3 #-}

suitable21 :: Double -> Maybe ([Double],Double)
suitable21 :: Double -> Maybe ([Double], Double)
suitable21 = ErrorImpact -> Double -> Maybe ([Double], Double)
suitable21G ErrorImpact
0
{-# INLINE suitable21 #-}

isRangeN :: Double -> Bool
isRangeN :: Double -> Bool
isRangeN Double
k = Double
k forall a. Ord a => a -> a -> Bool
>= Double
0.005 Bool -> Bool -> Bool
&& Double
k forall a. Ord a => a -> a -> Bool
<= Double
0.9
{-# INLINE isRangeN #-}

-- | The preferable range of the argument for 'suitable2' and 'suitable21' functions. For arguments
-- in this range the functions always have informative results.
isRangeNPref :: Double -> Bool
isRangeNPref :: Double -> Bool
isRangeNPref Double
k = Double
k forall a. Ord a => a -> a -> Bool
>= Double
0.005 Bool -> Bool -> Bool
&& Double
k forall a. Ord a => a -> a -> Bool
< (Double
2.0forall a. Fractional a => a -> a -> a
/Double
3.0)
{-# INLINE isRangeNPref #-}

{- | Allows to take  into account the sign of the absolute error of the aproximation. If the 
'ErrorImpact' parameter is equal to 0 , then absolute error can be of any sign,
otherwise the sign of it is the same as the sign of the 'ErrorImpact' argument.
-}
check1FracDecompG :: ErrorImpact -> Double -> Maybe ([Double], Double)
check1FracDecompG :: ErrorImpact -> Double -> Maybe ([Double], Double)
check1FracDecompG ErrorImpact
n Double
k 
 | Double
k forall a. Ord a => a -> a -> Bool
>= Double
0.005 Bool -> Bool -> Bool
&& Double
k forall a. Ord a => a -> a -> Bool
<= Double
0.501 = 
     let c :: Double
c = (Double
1.0forall a. Fractional a => a -> a -> a
/Double
k)
         ec :: Integer
ec = forall a. Integral a => ErrorImpact -> Double -> a
errImpact ErrorImpact
n Double
c
         err :: Double
err = Double
1.0forall a. Fractional a => a -> a -> a
/forall a b. (Integral a, Num b) => a -> b
fromIntegral Integer
ec forall a. Num a => a -> a -> a
- Double
k
         cs :: [Double]
cs = [forall a b. (Integral a, Num b) => a -> b
fromIntegral Integer
ec]
           in forall a. a -> Maybe a
Just ([Double]
cs, ErrorImpact -> [Double] -> Double -> Double
absErrUDecomp3I ErrorImpact
n [Double]
cs Double
k) 
 | Bool
otherwise = forall a. Maybe a
Nothing
{-# INLINE check1FracDecompG #-}

{- | Allows to take  into account the sign of the absolute error of the aproximation. If the 
'ErrorImpact' parameter is equal to 0 , then absolute error can be of any sign,
otherwise the sign of it is the same as the sign of the 'ErrorImpact' argument.
-}
check3FracDecompPartialG :: ErrorImpact -> Double -> Maybe ([Double],Double)
check3FracDecompPartialG :: ErrorImpact -> Double -> Maybe ([Double], Double)
check3FracDecompPartialG ErrorImpact
n = ErrorImpact -> [ErrorImpact] -> Double -> Maybe ([Double], Double)
check3FracDecompPartialPG ErrorImpact
n []
{-# INLINE check3FracDecompPartialG #-}

{- | Allows to take  into account the sign of the absolute error of the aproximation. If the 
'ErrorImpact' parameter is equal to 0 , then absolute error can be of any sign, 
otherwise the sign of it is the same as the sign of the 'ErrorImpact' argument.
-}
check3FracDecompPartialPG :: ErrorImpact -> [Int] -> Double -> Maybe ([Double],Double)
check3FracDecompPartialPG :: ErrorImpact -> [ErrorImpact] -> Double -> Maybe ([Double], Double)
check3FracDecompPartialPG ErrorImpact
n [ErrorImpact]
ns Double
k 
 | Double
k forall a. Ord a => a -> a -> Bool
>= Double
0.005 Bool -> Bool -> Bool
&& Double
k forall a. Ord a => a -> a -> Bool
<= Double
1 = 
     let !s2s :: [([Double], Double)]
s2s = forall a. [Maybe a] -> [a]
catMaybes forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a -> b) -> [a] -> [b]
map (ErrorImpact -> Double -> Maybe ([Double], Double)
suitable21G ErrorImpact
n) forall a b. (a -> b) -> a -> b
$ [Double]
lst2check in 
            if forall a. [a] -> Bool
null [([Double], Double)]
s2s 
                then forall a. Maybe a
Nothing 
                else let ([Double
a1,Double
b1],Double
err3) = forall (t :: * -> *) a.
Foldable t =>
(a -> a -> Ordering) -> t a -> a
minimumBy (\([Double]
_,Double
er0) ([Double]
_,Double
er1) -> forall a. Ord a => a -> a -> Ordering
compare (forall a. Num a => a -> a
abs Double
er0) (forall a. Num a => a -> a
abs Double
er1)) [([Double], Double)]
s2s
                         u1 :: Double
u1 = forall a b. (Integral a, Num b) => a -> b
fromIntegral forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (RealFrac a, Integral b) => a -> b
round forall a b. (a -> b) -> a -> b
$ Double
1.0forall a. Fractional a => a -> a -> a
/(Double
k forall a. Num a => a -> a -> a
+ Double
err3 forall a. Num a => a -> a -> a
- (Double
1.0forall a. Fractional a => a -> a -> a
/Double
a1 forall a. Num a => a -> a -> a
+ Double
1.0forall a. Fractional a => a -> a -> a
/forall a b. (Integral a, Num b) => a -> b
fromIntegral (forall a. Integral a => ErrorImpact -> Double -> a
errImpact ErrorImpact
n Double
b1))) 
                            in forall a. a -> Maybe a
Just (forall a. Ord a => [a] -> [a]
sort [Double
u1,Double
a1,forall a b. (Integral a, Num b) => a -> b
fromIntegral (forall a. Integral a => ErrorImpact -> Double -> a
errImpact ErrorImpact
n Double
b1)],Double
err3) 
 | Bool
otherwise = forall a. Maybe a
Nothing
      where !lst2check :: [Double]
lst2check = (\[Double]
ks -> let !upp :: Double
upp = Double
2.0forall a. Fractional a => a -> a -> a
/Double
3.0 in forall a b. (a -> b -> b) -> b -> [a] -> b
foldr (\Double
t [Double]
ys -> let !w :: Double
w = Double
k forall a. Num a => a -> a -> a
- Double
1.0forall a. Fractional a => a -> a -> a
/Double
t in if Double
w forall a. Ord a => a -> a -> Bool
>= Double
0.005 Bool -> Bool -> Bool
&& Double
w forall a. Ord a => a -> a -> Bool
<= Double
upp then Double
wforall a. a -> [a] -> [a]
:[Double]
ys else [Double]
ys) [] [Double]
ks) forall a b. (a -> b) -> a -> b
$ [forall a b. (Integral a, Num b) => a -> b
fromIntegral (forall a b. (RealFrac a, Integral b) => a -> b
ceiling (Double
1.0forall a. Fractional a => a -> a -> a
/Double
k))..forall a b. (Integral a, Num b) => a -> b
fromIntegral (forall a b. (RealFrac a, Integral b) => a -> b
truncate (Double
3.0forall a. Fractional a => a -> a -> a
/Double
k))] forall a. Monoid a => a -> a -> a
`mappend` forall a b. (a -> b) -> [a] -> [b]
map forall a b. (Integral a, Num b) => a -> b
fromIntegral [ErrorImpact]
ns
{-# INLINE check3FracDecompPartialPG #-}

{- | A variant of 'check3FracDecompPartialPG' where there is no possible equal 'Integral' values as
 the result.
-}
check3FracDecompPartialPG3 :: ErrorImpact -> [Int] -> Double -> Maybe ([Double],Double)
check3FracDecompPartialPG3 :: ErrorImpact -> [ErrorImpact] -> Double -> Maybe ([Double], Double)
check3FracDecompPartialPG3 ErrorImpact
n [ErrorImpact]
ns Double
k 
 | Double
k forall a. Ord a => a -> a -> Bool
>= Double
0.005 Bool -> Bool -> Bool
&& Double
k forall a. Ord a => a -> a -> Bool
<= Double
1 = 
    if forall a. [a] -> Bool
null [([Double], Double)]
s2s 
        then forall a. Maybe a
Nothing 
        else let ([Double
a1,Double
b1],Double
err3) = forall (t :: * -> *) a.
Foldable t =>
(a -> a -> Ordering) -> t a -> a
minimumBy (\([Double]
_,Double
er0) ([Double]
_,Double
er1) -> forall a. Ord a => a -> a -> Ordering
compare (forall a. Num a => a -> a
abs Double
er0) (forall a. Num a => a -> a
abs Double
er1)) [([Double], Double)]
s2s
                 u1 :: Double
u1 = forall a b. (Integral a, Num b) => a -> b
fromIntegral forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (RealFrac a, Integral b) => a -> b
round forall a b. (a -> b) -> a -> b
$ Double
1.0forall a. Fractional a => a -> a -> a
/(Double
k forall a. Num a => a -> a -> a
+ Double
err3 forall a. Num a => a -> a -> a
- (Double
1.0forall a. Fractional a => a -> a -> a
/Double
a1 forall a. Num a => a -> a -> a
+ Double
1.0forall a. Fractional a => a -> a -> a
/forall a b. (Integral a, Num b) => a -> b
fromIntegral (forall a. Integral a => ErrorImpact -> Double -> a
errImpact ErrorImpact
n Double
b1))) 
                    in forall a. a -> Maybe a
Just (forall a. Ord a => [a] -> [a]
sort [Double
u1,Double
a1,forall a b. (Integral a, Num b) => a -> b
fromIntegral (forall a. Integral a => ErrorImpact -> Double -> a
errImpact ErrorImpact
n Double
b1)],Double
err3) 
 | Bool
otherwise = forall a. Maybe a
Nothing
      where !s2s :: [([Double], Double)]
s2s = (\[ErrorImpact]
ks -> let !upp :: Double
upp = Double
2.0forall a. Fractional a => a -> a -> a
/Double
3.0 in forall a b. (a -> b -> b) -> b -> [a] -> b
foldr (\ErrorImpact
t [([Double], Double)]
ys -> let !w :: Double
w = Double
k forall a. Num a => a -> a -> a
- Double
1.0forall a. Fractional a => a -> a -> a
/forall a b. (Integral a, Num b) => a -> b
fromIntegral ErrorImpact
t in if Double
w forall a. Ord a => a -> a -> Bool
>= Double
0.005 Bool -> Bool -> Bool
&& Double
w forall a. Ord a => a -> a -> Bool
<= Double
upp then let !tt :: Maybe ([Double], Double)
tt = forall a.
Integral a =>
ErrorImpact -> a -> Double -> Maybe ([Double], Double)
suitable21G3 ErrorImpact
n ErrorImpact
t Double
w in if forall a. Maybe a -> Bool
isJust Maybe ([Double], Double)
tt then forall a. HasCallStack => Maybe a -> a
fromJust Maybe ([Double], Double)
ttforall a. a -> [a] -> [a]
:[([Double], Double)]
ys else [([Double], Double)]
ys else [([Double], Double)]
ys) [] [ErrorImpact]
ks) forall a b. (a -> b) -> a -> b
$ [forall a b. (RealFrac a, Integral b) => a -> b
ceiling (Double
1.0forall a. Fractional a => a -> a -> a
/Double
k)..forall a b. (RealFrac a, Integral b) => a -> b
truncate (Double
3.0forall a. Fractional a => a -> a -> a
/Double
k)] forall a. Monoid a => a -> a -> a
`mappend` [ErrorImpact]
ns
{-# INLINE check3FracDecompPartialPG3 #-}


{- | Allows to take  into account the sign of the absolute error of the aproximation. If the 
'ErrorImpact' parameter is equal to 0 , then absolute error can be of any sign,
otherwise the sign of it is the same as the sign of the 'ErrorImpact' argument.
-}
lessErrSimpleDecompPG :: ErrorImpact -> [Int] -> Double -> (Int,Maybe ([Double],Double),Double)
lessErrSimpleDecompPG :: ErrorImpact
-> [ErrorImpact]
-> Double
-> (ErrorImpact, Maybe ([Double], Double), Double)
lessErrSimpleDecompPG ErrorImpact
n [ErrorImpact]
ns Double
k = 
  (\[([Double], Double)]
ts -> if forall a. [a] -> Bool
null [([Double], Double)]
ts 
              then (ErrorImpact
0,forall a. Maybe a
Nothing,-Double
1.0) 
              else let p :: ([Double], Double)
p = forall (t :: * -> *) a.
Foldable t =>
(a -> a -> Ordering) -> t a -> a
minimumBy (forall a b. Ord a => (b -> a) -> b -> b -> Ordering
comparing (forall a. Num a => a -> a
abs forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a, b) -> b
snd)) [([Double], Double)]
ts in (forall a. [a] -> ErrorImpact
length (forall a b. (a, b) -> a
fst ([Double], Double)
p), forall a. a -> Maybe a
Just ([Double], Double)
p, forall a b. (a, b) -> b
snd ([Double], Double)
p))  forall b c a. (b -> c) -> (a -> b) -> a -> c
. 
                              forall a. [Maybe a] -> [a]
catMaybes forall a b. (a -> b) -> a -> b
$ [ErrorImpact -> Double -> Maybe ([Double], Double)
check1FracDecompG ErrorImpact
n Double
k,ErrorImpact -> Double -> Maybe ([Double], Double)
suitable21G ErrorImpact
n Double
k, ErrorImpact -> [ErrorImpact] -> Double -> Maybe ([Double], Double)
check3FracDecompPartialPG3 ErrorImpact
n [ErrorImpact]
ns Double
k]

{-| Allows to take  into account the sign of the absolute error of the aproximation. If the 
'ErrorImpact' parameter is equal to 0 , then absolute error can be of any sign,
otherwise the sign of it is the same as the sign of the 'ErrorImpact' argument.
-}
lessErrDenomsPG :: ErrorImpact -> [Int] -> Double -> [Integer]
lessErrDenomsPG :: ErrorImpact -> [ErrorImpact] -> Double -> [Integer]
lessErrDenomsPG ErrorImpact
n [ErrorImpact]
ns = 
  (\(ErrorImpact
_,Maybe ([Double], Double)
ks,Double
_) -> if forall a. Maybe a -> Bool
isNothing Maybe ([Double], Double)
ks 
                    then [] 
                    else forall a b. (a -> b) -> [a] -> [b]
map (forall a. Integral a => ErrorImpact -> Double -> a
errImpact ErrorImpact
n) forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a, b) -> a
fst forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. HasCallStack => Maybe a -> a
fromJust forall a b. (a -> b) -> a -> b
$ Maybe ([Double], Double)
ks) forall b c a. (b -> c) -> (a -> b) -> a -> c
. ErrorImpact
-> [ErrorImpact]
-> Double
-> (ErrorImpact, Maybe ([Double], Double), Double)
lessErrSimpleDecompPG ErrorImpact
n [ErrorImpact]
ns
{-# INLINE lessErrDenomsPG #-}

--------------------------------------------

-- | Tries to approximate the fraction by just one unit fraction. Can be used for the numbers
-- between 0.005 and 0.501.
check1FracDecomp :: Double -> Maybe ([Double], Double)
check1FracDecomp :: Double -> Maybe ([Double], Double)
check1FracDecomp = ErrorImpact -> Double -> Maybe ([Double], Double)
check1FracDecompG ErrorImpact
0
{-# INLINE check1FracDecomp #-}

{- | Function to find the less by absolute value error approximation. One of the denominators is
taken from the range [2..10]. The two others are taken from the appropriate 'suitable21' 
applicattion.
-}
check3FracDecompPartial :: Double -> Maybe ([Double],Double)
check3FracDecompPartial :: Double -> Maybe ([Double], Double)
check3FracDecompPartial = ErrorImpact -> Double -> Maybe ([Double], Double)
check3FracDecompPartialG ErrorImpact
0
{-# INLINE check3FracDecompPartial #-}

{- | Extended version of the 'check3FracDecompPartial' with the first denominator being taken not
 - only from the [2..10], but also from the custom user provided list. 
 - -}
check3FracDecompPartialP :: [Int] -> Double -> Maybe ([Double],Double)
check3FracDecompPartialP :: [ErrorImpact] -> Double -> Maybe ([Double], Double)
check3FracDecompPartialP = ErrorImpact -> [ErrorImpact] -> Double -> Maybe ([Double], Double)
check3FracDecompPartialPG ErrorImpact
0
{-# INLINE check3FracDecompPartialP #-}


lessErrSimpleDecompP :: [Int] -> Double -> (Int,Maybe ([Double],Double),Double)
lessErrSimpleDecompP :: [ErrorImpact]
-> Double -> (ErrorImpact, Maybe ([Double], Double), Double)
lessErrSimpleDecompP = ErrorImpact
-> [ErrorImpact]
-> Double
-> (ErrorImpact, Maybe ([Double], Double), Double)
lessErrSimpleDecompPG ErrorImpact
0

-- | Returns a list of denominators for fraction decomposition using also those ones from the the list provided as the first argument. Searches for the least error from the checked ones.
lessErrDenomsP :: [Int] -> Double -> [Integer]
lessErrDenomsP :: [ErrorImpact] -> Double -> [Integer]
lessErrDenomsP = ErrorImpact -> [ErrorImpact] -> Double -> [Integer]
lessErrDenomsPG ErrorImpact
0
{-# INLINE lessErrDenomsP #-}

-- | Returns a unit fraction decomposition into 4 unit fractions. For the cases where the fraction
-- can be represented as a sum of three or less unit fractions, the last element in the resulting
-- list is really related to the floating-point arithmetic rounding errors and it depends on the
-- machine architecture and the realization of the floating-point arithmetic operations.
-- Almost any 'Double' value inside the [0.005, 2/3] can be rather well approximated by the sum of 4
-- unit fractions from the function here. There are also some intervals in the (2/3, 1] that have
-- also good approximations, though not every fraction is approximated well here.
lessErrSimpleDecomp4PG :: ErrorImpact -> [Int] -> Double -> ([Integer], Double)
lessErrSimpleDecomp4PG :: ErrorImpact -> [ErrorImpact] -> Double -> ([Integer], Double)
lessErrSimpleDecomp4PG ErrorImpact
n [ErrorImpact]
ns Double
k = 
  let !ints :: [Integer]
ints = ErrorImpact -> [ErrorImpact] -> Double -> [Integer]
lessErrDenomsPG (-ErrorImpact
1) [ErrorImpact]
ns Double
k 
      !revs :: [Double]
revs = forall a b. (a -> b) -> [a] -> [b]
map (\Integer
t -> Double
1.0forall a. Fractional a => a -> a -> a
/ forall a b. (Integral a, Num b) => a -> b
fromIntegral Integer
t) [Integer]
ints
      !s :: Double
s = forall a. Num a => [a] -> a
sum [Double]
revs
      !err :: Double
err = Double
s forall a. Num a => a -> a -> a
- Double
k
      !reverr :: Double
reverr = Double
1.0 forall a. Fractional a => a -> a -> a
/ forall a. Num a => a -> a
abs Double
err
      !next :: Integer
next = forall a. Integral a => ErrorImpact -> Double -> a
errImpact ErrorImpact
n Double
reverr
      !err4 :: Double
err4 = Double
err forall a. Num a => a -> a -> a
+ Double
1.0 forall a. Fractional a => a -> a -> a
/ forall a b. (Integral a, Num b) => a -> b
fromIntegral Integer
next in ([Integer]
ints forall a. Monoid a => a -> a -> a
`mappend` [Integer
next], Double
err4)

-- | Returns a unit fraction decomposition into 5 unit fractions. For the cases where the fraction
-- can be represented as a sum of three or less unit fractions, the last element(s) in the resulting
-- list is (are) really related to the floating-point arithmetic rounding errors and it depends on the
-- machine architecture and the realization of the floating-point arithmetic operations.
-- Almost any 'Double' value inside the [0.005, 2/3] can be rather well approximated by the sum of 5
-- unit fractions from the function here. There are also some intervals in the (2/3, 1] that have
-- also good approximations, though not every fraction is approximated well here.
lessErrSimpleDecomp5PG :: ErrorImpact -> [Int] -> Double -> ([Integer], Double)
lessErrSimpleDecomp5PG :: ErrorImpact -> [ErrorImpact] -> Double -> ([Integer], Double)
lessErrSimpleDecomp5PG ErrorImpact
n [ErrorImpact]
ns Double
k = 
  let (![Integer]
ints, !Double
err4) = ErrorImpact -> [ErrorImpact] -> Double -> ([Integer], Double)
lessErrSimpleDecomp4PG (-ErrorImpact
1) [ErrorImpact]
ns Double
k 
      !reverr :: Double
reverr = Double
1.0 forall a. Fractional a => a -> a -> a
/ forall a. Num a => a -> a
abs Double
err4
      !next :: Integer
next = forall a. Integral a => ErrorImpact -> Double -> a
errImpact ErrorImpact
n Double
reverr
      !err5 :: Double
err5 = Double
err4 forall a. Num a => a -> a -> a
+ Double
1.0 forall a. Fractional a => a -> a -> a
/ forall a b. (Integral a, Num b) => a -> b
fromIntegral Integer
next in ([Integer]
ints forall a. Monoid a => a -> a -> a
`mappend` [Integer
next], Double
err5)