packages feed

aern2-real-0.2.7.0: examples/AERN2/Real/Examples/ClosestPairDist.hs

{-# LANGUAGE PartialTypeSignatures #-}
{-# OPTIONS_GHC -Wno-missing-signatures #-}
{-# OPTIONS_GHC -Wno-partial-type-signatures #-}
{-|
    Module      :  AERN2.Real.Examples..ClosestPairDist
    Description :  Example: Computing shortest distance among a set of 1D points
    Copyright   :  (c) Michal Konecny
    License     :  BSD3

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

    Example: Computing shortest distance among a set of 1D points.

    You can run this file in ghci.
    If you installed AERN2 using the official instructions,
    you can start ghci using the following command in the base
    folder:

    @
    stack repl aern2-real/examples/AERN2/Real/Examples/ClosestPairDist.hs
    @
-}
module AERN2.Real.Examples.ClosestPairDist where

import MixedTypesNumPrelude
-- import qualified Prelude as P
-- import Text.Printf

import Test.QuickCheck
import qualified Data.List as List

import AERN2.Real

----------------------------------
-- Finding the smallest distance within a set of real numbers
----------------------------------

distance :: 
  (CanAbsSameType t, CanSubSameType t)
  =>
  (t, t) -> t
distance (a,b) = abs (a-b)

closestPairDist_naive :: 
  (CanMinMaxSameType t, CanAbsSameType t, CanSubSameType t) 
  =>
  [t] -> t
closestPairDist_naive pts
  | length pts < 2 = error "closestPairDist_naive: too few points"
  | otherwise =
      (foldl1 min (map distance (distinctPairs pts)))
  where
  distinctPairs :: [t] -> [(t,t)]
  distinctPairs xs = [(x,y) | (x:rest) <- tails1 xs, y <- rest]

  {-| non-empty tails -}
  tails1 :: [t] -> [[t]]
  tails1 list =
    take (length list - 1) $ List.tails list

{- a version that splits, recurses and merges the results -}
closestPairDist_split ::
  (RealNumber r, CanMinMaxSameType r, CanAbsSameType r) 
  => 
  [r] -> r
closestPairDist_split pts
  | length ptsL < 2 || length ptsR < 2 =
      closestPairDist_naive pts
  | otherwise =
      recurseAndMerge
  where
  (ptsL,ptsR) = List.partition isCertainlyLeft pts
    where
    isCertainlyLeft x = 
      isCertainlyTrue $ select (x < a) (x > a - 0.5^100)
    a = average pts
  recurseAndMerge =
    foldl1 min [dL, dLR, dR]
    where
    dL = closestPairDist_split ptsL
    dLR = distance (largest ptsL, smallest ptsR)
    dR = closestPairDist_split ptsR
  
average :: (HasIntegers t, CanAddSameType t, CanDivBy t Integer) => [t] -> t
average xs = (sum xs) / (length xs)

largest :: (CanMinMaxSameType t) => [t] -> t
largest pts = foldl1 max pts

smallest :: (CanMinMaxSameType t) => [t] -> t
smallest pts = foldl1 min pts

{-
  Helper functions for running tests by hand.
  -}

closestPairDist_run ::
  (RealNumber r, CanSinCosSameType r, CanMinMaxSameType r, CanAbsSameType r)
  =>
  ([r] -> r) -> 
  Integer -> r
closestPairDist_run (closestPairDist :: [t] -> t) n =
  closestPairDist [sin (convertExactly i :: t) | i <- [1..n]]

closestPairDist_run_naive :: 
  (RealNumber r, CanSinCosSameType r, CanMinMaxSameType r, CanAbsSameType r) 
  => 
  Integer -> r
closestPairDist_run_naive =
  closestPairDist_run closestPairDist_naive 

closestPairDist_run_split ::
  (RealNumber r, CanSinCosSameType r, CanMinMaxSameType r, CanAbsSameType r) 
  => 
  Integer -> r
closestPairDist_run_split =
  closestPairDist_run $ closestPairDist_split

closestPairDist_run_naive_CReal :: Integer -> CReal
closestPairDist_run_naive_CReal = closestPairDist_run_naive

closestPairDist_run_naive_WCP :: Integer -> CReal
closestPairDist_run_naive_WCP n = crealFromWithCurrentPrec $ closestPairDist_run_naive n

closestPairDist_run_split_CReal :: Integer -> CReal
closestPairDist_run_split_CReal = closestPairDist_run_split

closestPairDist_run_split_WCP :: Integer -> CReal
closestPairDist_run_split_WCP n = crealFromWithCurrentPrec $ closestPairDist_run_split n


{- Example runs:

*AERN2.Real.Examples.ClosestPairDist> closestPairDist_run_naive_CReal 1000 ? (prec 1000)
[0.00000013295546744391165086... ± ~0.0000 ~2^(-1221)]
(13.80 secs, 12,017,593,904 bytes)

*AERN2.Real.Examples.ClosestPairDist> closestPairDist_run_naive_WCP 1000 ? (prec 1000)
[0.00000013295546744391165086... ± ~0.0000 ~2^(-1221)]
(7.12 secs, 9,187,727,688 bytes)

*AERN2.Real.Examples.ClosestPairDist> closestPairDist_run_split_CReal 1000 ? (prec 1000)
[0.00000013295546744391165086... ± ~0.0000 ~2^(-1221)]
(2.59 secs, 4,659,949,752 bytes)

*AERN2.Real.Examples.ClosestPairDist> closestPairDist_run_split_WCP 1000 ? (prec 1000)
[0.00000013295546744391165086... ± ~0.0000 ~2^(-1221)]
(1.11 secs, 2,245,453,016 bytes)

-}

{- specification and randomised tests -}

closestPairDist_spec :: 
  _ =>
  ([r] -> r) -> (r -> t) -> [b] -> Property
closestPairDist_spec closestPairDist (getFinite :: r -> t) numbers =
  (length numbers) < 2
  .||.
  (getFinite (closestPairDist numbersR)) ?==?$ (closestPairDist_naive numbers)
  where
  numbersR = map convertExactly numbers :: [r]
  a ?==?$ b = printArgsIfFails2 "?==?" (?==?) a b

closestPairDist_runTests1 :: IO ()
closestPairDist_runTests1 =
  quickCheck (closestPairDist_spec (closestPairDist_split :: [CReal] -> CReal) (?bits 100) :: [Integer] -> Property)

sample_integers = sample' (arbitrary :: Gen [Integer]) >>= mapM_ print
sample_rationals = sample' (arbitrary :: Gen [Rational]) >>= mapM_ print