packages feed

aern2-mfun-0.2.9.0: src/AERN2/BoxFun/Box.hs

{-# OPTIONS_GHC -Wno-orphans #-}
module AERN2.BoxFun.Box where

import qualified Prelude as Prelude
import MixedTypesNumPrelude
import AERN2.MP.Dyadic
import AERN2.MP.Ball
import AERN2.Linear.Vector.Type (Vector, (!))
import qualified AERN2.Linear.Vector.Type as V
import AERN2.Util.Util

type Box = Vector (CN MPBall)

-- instance HasEqAsymmetric Box Box where
--     type EqCompareType Box Box = (CN Kleenean)
--     equalTo box0 box1 = 
--         V.foldl' (&&) (cn CertainTrue) $ V.zipWith equalTo box0 box1

-- intersection :: Box -> Box -> Maybe Box
-- intersection = undefined

intersectionCertainlyEmpty :: Box -> Box -> Bool
intersectionCertainlyEmpty vx vy =
    V.foldl' (||) False $ V.zipWith ballIntersectionCertainlyEmpty vx vy
    where 
    ballIntersectionCertainlyEmpty x y = 
        (lx !>! ry || rx !<! ly)
        where
        (lx, rx) = endpointsAsIntervals x
        (ly, ry) = endpointsAsIntervals y

nonEmptyIntersection :: Box -> Box -> Box
nonEmptyIntersection vx vy = 
    V.zipWith intersectCN vx vy

instance IsBall Box where
    type CentreType (Box) = Box
    centre v = V.map (\x -> (cnMPBallP (getPrecision x) . centre) x) v

inftyNorm :: Box -> CN MPBall
inftyNorm box = 
    V.foldl' (\n x -> max n (abs x)) (cn $ mpBall 0) box

ellOneNorm :: Box -> CN MPBall
ellOneNorm box = 
    V.foldl' (\n x -> n + (abs x)) (cn $ mpBall 0) box

width :: Box -> CN MPBall
width box = 
    V.foldl' (\n x -> max n (2 * ((fmap mpBall) $ (fmap radius) x) ) ) (cn $ mpBall 0) box

widestDirection :: Box -> Integer
widestDirection box =
    aux (V.length box - 1) (V.length box - 1) (dyadic 0)
    where
    aux k i lth =
        if k < 0 then 
            i
        else
            let 
                x    = box ! k
                lth' = 
                    2 * (dyadic $ radius $ unCN x) -- TODO: unsafe
            in
                if (lth' > lth) then 
                    aux (k - 1) k lth'
                else 
                    aux (k - 1) i lth


bisect :: Integer -> Box -> (Box, Box)
bisect k box =
    if exponent_ > 0
    && (abs $ mc - lbc) < (dyadic 0.5)^exponent_ then
        (setPrecision (increasePrecision p) lb, setPrecision (increasePrecision p) rb)
    else 
        (lb, rb)
    where
    exponent_      = integer p - ilog
    NormBits ilog = 2 + (getNormLog $  mpBall $ 1 + abs lbc )
    lbc = unCN (centre $ lb ! k)
    -- rbc = unCN (centre $ rb ! k)
    mc  = unCN (centre $ m)
    increasePrecision p1 =
        p1 + (prec $ (integer p1) `Prelude.div` 2)
    lb = setPrecision p leftBox
    rb = setPrecision p rightBox
    p   = getPrecision box
    interval = box ! k
    m = (fmap $ mpBallP p) $ (fmap centre) interval
    (l, r) = endpointsAsIntervals interval
    leftBox  = V.imap (\i x -> if i == k then fromEndpointsAsIntervals l m else x) box
    rightBox = V.imap (\i x -> if i == k then fromEndpointsAsIntervals m r else x) box

-- Bisects a into 2^d boxes of the same size, where d is the dimension of the given box
fullBisect :: Box -> [Box]
fullBisect b =
    case V.length b of
        0 -> [b]
        l ->
            -- y is the dimension bisected in the current iteration
            -- x is a bisection of the previous dimension (tail recursion)
            concatMap (\x -> map (\y -> x V.+++ V.singleton y) (bisectDimension (l-1))) (fullBisect (V.take (fromIntegral (l-1)) b))

            where
                bisectDimension n = [fst bn ! n, snd bn ! n]
                    where bn = bisect n b

-- Get the endpoints of a box as a list containing a pair of MPBalls for each dimension
getEndpoints :: Box -> [(MPBall, MPBall)]
getEndpoints b  = 
    case V.length b of
        0 -> []
        _ -> endpointsAsIntervals (unCN (b ! 0)) : getEndpoints (V.drop (int 1) b)

lowerBounds :: Box -> Box
lowerBounds = V.map lowerBound

upperBounds :: Box -> Box
upperBounds = V.map upperBound

instance 
    CanNeg Box
    where
    type NegType Box = Box
    negate box = V.map (\x -> -x) box
    
createEnclosingBox :: Box -> Box -> Box
createEnclosingBox box1 box2 =
    enclosingBox
    where
        indexedBox1 = V.zip (V.fromList [0 .. integer (V.length box1) - 1]) box1
        enclosingBox = 
            V.map 
            (\(i, x) -> 
                let
                    y = box2 V.! i
                    (l, r) = endpointsAsIntervals x
                    (l', r') = endpointsAsIntervals y
                    newL = min l l'
                    newR = max r r'
                in
                    fromEndpointsAsIntervals newL newR)
            indexedBox1

intersectList :: [Box] -> Box
intersectList []            = V.empty
intersectList [b]           = b
intersectList [b1,b2]       = if intersectionCertainlyEmpty b1 b2 then V.empty else nonEmptyIntersection b1 b2
intersectList (b1:b2:bs)    = if intersectionCertainlyEmpty b1 b2 then V.empty else intersectList $ nonEmptyIntersection b1 b2 : bs