{-# OPTIONS_GHC -fno-warn-missing-methods #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE UndecidableInstances #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE DeriveDataTypeable #-} {-| Module : Data.Number.ER.RnToRm.Approx.Tuples Description : a list of approximations over the same domain Copyright : (c) Michal Konecny License : BSD3 Maintainer : mik@konecny.aow.cz Stability : experimental Portability : portable Lists of function approximations over the same domain. -} module Data.Number.ER.RnToRm.Approx.Tuple ( ERFnTuple(..) ) where import qualified Data.Number.ER.RnToRm.Approx as FA import qualified Data.Number.ER.Real.Approx as RA import qualified Data.Number.ER.Real.Approx.Elementary as RAEL import qualified Data.Number.ER.Real.DomainBox as DBox import Data.Number.ER.BasicTypes import Data.Typeable import Data.Generics.Basics import Data.Binary {-| A tuple of function approximations allowing one to get from functions @R^n->R@ to a function @R^n -> R^m@. -} data ERFnTuple fa = ERFnTuple { erfnTuple :: [fa] } deriving (Typeable, Data) instance (Binary a) => Binary (ERFnTuple a) where put (ERFnTuple a) = put a get = get >>= \a -> return (ERFnTuple a) tuplesLift1 :: (fa -> fa) -> (ERFnTuple fa) -> (ERFnTuple fa) tuplesLift1 op (ERFnTuple fas) = ERFnTuple (map op fas) tuplesLift2 :: (Show fa) => String -> (fa -> fa -> fa) -> (ERFnTuple fa) -> (ERFnTuple fa) -> (ERFnTuple fa) tuplesLift2 callerLocation op f1@(ERFnTuple fas1) f2@(ERFnTuple fas2) | length fas1 == length fas2 = ERFnTuple $ zipWith op fas1 fas2 | otherwise = error $ callerLocation ++ "incompatible lengths: " ++ show (length fas1) ++ " != " ++ show (length fas2) ++ "\n first argument = \n" ++ show fas1 ++ "\n second argument = \n" ++ show fas2 tuplesSplit :: (fa -> (fa, fa)) -> (ERFnTuple fa) -> (ERFnTuple fa, ERFnTuple fa) tuplesSplit op f@(ERFnTuple fas) = (ERFnTuple fas1, ERFnTuple fas2) where (fas1, fas2) = unzip $ map op fas -- version with Map.Map: --data ERFnTuple fa = -- ERFnTuple (Map.Map varid fa) -- deriving (Typeable, Data) -- --tuplesLift1 :: -- (fa -> fa) -> -- (ERFnTuple fa) -> (ERFnTuple fa) --tuplesLift1 op (ERFnTuple fas) = -- ERFnTuple (Map.map op fas) -- --tuplesLift2 :: -- (fa -> fa -> fa) -> -- (ERFnTuple fa) -> (ERFnTuple fa) -> (ERFnTuple fa) --tuplesLift2 op f1@(ERFnTuple fas1) f2@(ERFnTuple fas2) -- | Map.keys fas1 == Map.keys fas2 = -- ERFnTuple $ Map.intersectionWith op fas1 fas2 -- | otherwise = -- error $ -- "ERFnTuple: incompatible keys: " -- ++ show (Map.keys fas1) ++ "\n*****\n" ++ show (Map.keys fas2) -- --tuplesSplit :: -- (fa -> (fa, fa)) -> -- (ERFnTuple fa) -> (ERFnTuple fa, ERFnTuple fa) --tuplesSplit op f@(ERFnTuple fas) = -- (ERFnTuple fas1, ERFnTuple fas2) -- where -- fas1 = Map.map fst fas12 -- fas2 = Map.map snd fas12 -- fas12 = Map.map op fas instance (FA.ERFnDomApprox box varid domra ranra fa) => Show (ERFnTuple fa) where show f@(ERFnTuple fas) = concat $ map showFA $ zip [0,1..] fas where showFA (fnname, fa) = "\n>>> Function " ++ show fnname ++ ":" ++ show fa instance (FA.ERFnApprox box varid domra ranra fa) => Eq (ERFnTuple fa) where (ERFnTuple fas1) == (ERFnTuple fas2) = fas1 == fas2 instance (FA.ERFnApprox box varid domra ranra fa, Ord fa) => Ord (ERFnTuple fa) where compare (ERFnTuple fas1) (ERFnTuple fas2) = compare fas1 fas2 instance (FA.ERFnDomApprox box varid domra ranra fa) => Num (ERFnTuple fa) where fromInteger n = ERFnTuple [fromInteger n] negate = tuplesLift1 negate (+) = tuplesLift2 "ERFnTuple: +: " (+) (*) = tuplesLift2 "ERFnTuple: *: " (*) instance (FA.ERFnDomApprox box varid domra ranra fa) => Fractional (ERFnTuple fa) where fromRational r = ERFnTuple [fromRational r] recip = tuplesLift1 recip instance (FA.ERFnDomApprox box varid domra ranra fa) => RA.ERApprox (ERFnTuple fa) where getGranularity (ERFnTuple fas) = foldl max 10 $ map RA.getGranularity fas setGranularity gran = tuplesLift1 (RA.setGranularity gran) setMinGranularity gran = tuplesLift1 (RA.setMinGranularity gran) f1 /\ f2 = tuplesLift2 "ERFnTuple: /\\: " (RA./\) f1 f2 intersectMeasureImprovement ix f1@(ERFnTuple fas1) f2@(ERFnTuple fas2) | length fas1 == length fas2 = (ERFnTuple fasIsect, ERFnTuple fasImpr) | otherwise = error $ show $ f1 RA./\ f2 where (fasIsect, fasImpr) = unzip $ zipWith (RA.intersectMeasureImprovement ix) fas1 fas2 leqReals f1@(ERFnTuple fas1) f2@(ERFnTuple fas2) | length fas1 == length fas2 = leqTuple $ zipWith RA.leqReals fas1 fas2 | otherwise = error $ show $ f1 RA./\ f2 where leqTuple [] = Just True leqTuple _ = error $ "ERFnTuple: leqReals not implemented" instance (FA.ERFnDomApprox box varid domra ranra fa, RA.ERIntApprox fa) => RA.ERIntApprox (ERFnTuple fa) where -- doubleBounds = :: ira -> (Double, Double) -- floatBounds :: ira -> (Float, Float) -- integerBounds :: ira -> (ExtendedInteger, ExtendedInteger) bisectDomain maybePt f@(ERFnTuple fas) = case maybePt of Nothing -> tuplesSplit (RA.bisectDomain Nothing) f Just (ERFnTuple fasPt) -> (ERFnTuple fas1, ERFnTuple fas2) where (fas1, fas2) = unzip $ map (\(fa, pt) -> RA.bisectDomain (Just pt) fa) $ zip fas fasPt bounds = tuplesSplit RA.bounds f1 \/ f2 = tuplesLift2 "ERFnTuple: \\/: " (RA.\/) f1 f2 instance (FA.ERFnDomApprox box varid domra ranra fa, RAEL.ERApproxElementary fa) => RAEL.ERApproxElementary (ERFnTuple fa) where abs ix = tuplesLift1 $ RAEL.abs ix exp ix = tuplesLift1 $ RAEL.exp ix log ix = tuplesLift1 $ RAEL.log ix sin ix = tuplesLift1 $ RAEL.sin ix cos ix = tuplesLift1 $ RAEL.cos ix atan ix = tuplesLift1 $ RAEL.atan ix instance (FA.ERFnDomApprox box varid domra ranra fa) => FA.ERFnApprox box varid domra ranra (ERFnTuple fa) where check prgLocation (ERFnTuple fs) = ERFnTuple $ map checkComp $ zip [0..] fs where checkComp (n, f) = FA.check (prgLocation ++ "fn" ++ show n ++ ": ") f domra2ranra (ERFnTuple (fa:_)) d = FA.domra2ranra fa d ranra2domra (ERFnTuple (fa:_)) r = FA.ranra2domra fa r setMaxDegree maxDegree = tuplesLift1 (FA.setMaxDegree maxDegree) getTupleSize (ERFnTuple fas) = length fas tuple fs | sameDomains doms = ERFnTuple $ concat $ map erfnTuple fs | otherwise = error $ "ERFnTuple: FA.tuple: incompatible domains:\n " ++ (unlines $ map show fs) where sameDomains [_] = True sameDomains (a : rest@(b : _)) = sameab && (sameDomains rest) where sameab = and $ map snd $ DBox.zipWithDefault RA.bottomApprox RA.equalApprox a b doms = map FA.dom fs applyTupleFn tupleFn (ERFnTuple fs) = FA.tuple $ tupleFn $ map (\fa -> ERFnTuple [fa]) fs volume (ERFnTuple fas) = sum $ map (FA.volume) fas scale ratio = tuplesLift1 (FA.scale ratio) partialIntersect ix substitutions = tuplesLift2 "ERFnTuple: partialIntersect: " $ FA.partialIntersect ix substitutions eval ptBox (ERFnTuple fas) = concat $ map (FA.eval ptBox) fas partialEval substitutions = tuplesLift1 $ FA.partialEval substitutions instance (FA.ERFnDomApprox box varid domra ranra fa) => FA.ERFnDomApprox box varid domra ranra (ERFnTuple fa) where dom (ERFnTuple (fa:_)) = FA.dom fa bottomApprox domB tupleSize = ERFnTuple $ replicate tupleSize $ FA.bottomApprox domB 1 const domB vals = ERFnTuple $ map (\v -> FA.const domB [v]) vals proj domB i = ERFnTuple [FA.proj domB i] bisect var maybePt = tuplesSplit $ FA.bisect var maybePt integrate ix (ERFnTuple fasD) x integdomBox origin (ERFnTuple fasInit) = ERFnTuple $ map integ $ zip fasD fasInit where integ (faD, faInit) = FA.integrate ix faD x integdomBox origin faInit integrateMeasureImprovement ix (ERFnTuple fasD) x integdomBox origin (ERFnTuple fasP) = (ERFnTuple fasIsect, ERFnTuple fasImpr) where (fasIsect, fasImpr) = unzip $ map integ $ zip fasD fasP integ (faD, faP) = FA.integrateMeasureImprovement ix faD x integdomBox origin faP