{-# LANGUAGE TypeFamilies #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE ImplicitParams #-} {-| Module : Numeric.AERN.RealArithmetic.NumericOrderRounding.MixedFieldOps Description : rounded basic arithmetic operations mixing 2 types Copyright : (c) Michal Konecny License : BSD3 Maintainer : mikkonecny@gmail.com Stability : experimental Portability : portable Rounded basic arithmetical operations mixing 2 types. This module is hidden and reexported via its parent NumericOrderRounding. -} module Numeric.AERN.RealArithmetic.NumericOrderRounding.MixedFieldOps where import Numeric.AERN.RealArithmetic.NumericOrderRounding.FieldOps import Numeric.AERN.RealArithmetic.NumericOrderRounding.Conversion import Numeric.AERN.RealArithmetic.ExactOps import Numeric.AERN.Basics.Exception import Numeric.AERN.Basics.Effort import Numeric.AERN.RealArithmetic.Laws import Numeric.AERN.RealArithmetic.Measures import qualified Numeric.AERN.Basics.NumericOrder as NumOrd import Numeric.AERN.Basics.NumericOrder.OpsImplicitEffort import Control.Exception import Data.Maybe import Test.QuickCheck import Test.Framework (testGroup, Test) import Test.Framework.Providers.QuickCheck2 (testProperty) class RoundedMixedAddEffort t tn where type MixedAddEffortIndicator t tn mixedAddDefaultEffort :: t -> tn -> MixedAddEffortIndicator t tn class (RoundedMixedAddEffort t tn) => RoundedMixedAdd t tn where mixedAddUpEff :: MixedAddEffortIndicator t tn -> t -> tn -> t mixedAddDnEff :: MixedAddEffortIndicator t tn -> t -> tn -> t {- tools to easily make a RoundedMixedAdd instance via the composition of conversion and homogeneous addition -} type MixedAddEffortIndicatorByConversion t tn = (AddEffortIndicator t, ConvertEffortIndicator tn t) mixedAddDefaultEffortByConversion d n = (addDefaultEffort d, convertDefaultEffort n d) mixedAddUpEffByConversion :: (Convertible tn t, RoundedAdd t, Show tn) => (AddEffortIndicator t, ConvertEffortIndicator tn t) -> t -> tn -> t mixedAddUpEffByConversion (effAdd, effConv) d n = addUpEff effAdd nUp d where nUp = case convertUpEff effConv n of (Just nUp) -> nUp _ -> throw $ AERNException $ "conversion failed during mixed addition: n = " ++ show n mixedAddDnEffByConversion :: (Convertible tn t, RoundedAdd t, Show tn) => (AddEffortIndicator t, ConvertEffortIndicator tn t) -> t -> tn -> t mixedAddDnEffByConversion (effAdd, effConv) d n = addDnEff effAdd nDn d where nDn = case convertDnEff effConv n of (Just nDn) -> nDn _ -> throw $ AERNException $ "conversion failed during mixed addition: n = " ++ show n {- properties of mixed addition -} propMixedAddEqualsConvert :: (NumOrd.PartialComparison t, Convertible tn t, RoundedMixedAdd t tn, RoundedAdd t, Show t, HasLegalValues t, Show (MixedAddEffortIndicator t tn), EffortIndicator (MixedAddEffortIndicator t tn), Show (ConvertEffortIndicator tn t), EffortIndicator (ConvertEffortIndicator tn t), Show (AddEffortIndicator t), EffortIndicator (AddEffortIndicator t), Show (NumOrd.PartialCompareEffortIndicator t), EffortIndicator (NumOrd.PartialCompareEffortIndicator t) ) => t -> tn -> (NumOrd.PartialCompareEffortIndicator t, (MixedAddEffortIndicator t tn, AddEffortIndicator t, ConvertEffortIndicator tn t)) -> (NumOrd.UniformlyOrderedSingleton t) -> tn -> Bool propMixedAddEqualsConvert sampleN sample initEffort (NumOrd.UniformlyOrderedSingleton d) n = equalRoundingUpDn "mixed addition by conversion" expr1Up expr1Dn expr2Up expr2Dn NumOrd.pLeqEff initEffort where expr1Up (effMAdd,_,_) = let (+^|) = mixedAddUpEff effMAdd in d +^| n expr1Dn (effMAdd,_,_) = let (+.|) = mixedAddDnEff effMAdd in d +.| n expr2Up (_,effAdd,effConv) = let (+^) = addUpEff effAdd in d +^ (fromJust $ convertUpEff effConv n) expr2Dn (_,effAdd,effConv) = let (+.) = addDnEff effAdd in d +. (fromJust $ convertDnEff effConv n) class RoundedMixedMultiplyEffort t tn where type MixedMultEffortIndicator t tn mixedMultDefaultEffort :: t -> tn -> MixedMultEffortIndicator t tn class (RoundedMixedMultiplyEffort t tn) => RoundedMixedMultiply t tn where mixedMultUpEff :: MixedMultEffortIndicator t tn -> t -> tn -> t mixedMultDnEff :: MixedMultEffortIndicator t tn -> t -> tn -> t {- tools to easily make a RoundedMixedMultiply instance via the composition of conversion and homogeneous addition -} type MixedMultEffortIndicatorByConversion t tn = (MultEffortIndicator t, ConvertEffortIndicator tn t, NumOrd.MinmaxEffortIndicator t) mixedMultDefaultEffortByConversion d n = (addDefaultEffort d, convertDefaultEffort n d, NumOrd.minmaxDefaultEffort d) mixedMultUpEffByConversion :: (Convertible tn t, RoundedMultiply t, NumOrd.RoundedLattice t, Show tn) => (MultEffortIndicator t, ConvertEffortIndicator tn t, NumOrd.MinmaxEffortIndicator t) -> t -> tn -> t mixedMultUpEffByConversion (effMult, effConv, effMinmax) d n = NumOrd.maxUpEff effMinmax (multUpEff effMult d nDn) (multUpEff effMult d nUp) where (nUp, nDn) = case (convertUpEff effConv n, convertDnEff effConv n) of (Just nUp, Just nDn) -> (nUp, nDn) _ -> throw $ AERNException $ "conversion failed during mixed multiplication: n = " ++ show n mixedMultDnEffByConversion :: (Convertible tn t, RoundedMultiply t, NumOrd.RoundedLattice t, Show tn) => (MultEffortIndicator t, ConvertEffortIndicator tn t, NumOrd.MinmaxEffortIndicator t) -> t -> tn -> t mixedMultDnEffByConversion (effMult, effConv, effMinmax) d n = NumOrd.minDnEff effMinmax (multDnEff effMult d nDn) (multDnEff effMult d nUp) where (nUp, nDn) = case (convertUpEff effConv n, convertDnEff effConv n) of (Just nUp, Just nDn) -> (nUp, nDn) _ -> throw $ AERNException $ "conversion failed during mixed multiplication: n = " ++ show n {- properties of mixed multiplication -} propMixedMultEqualsConvert :: (NumOrd.PartialComparison t, NumOrd.RoundedLattice t, Convertible tn t, RoundedMixedMultiply t tn, RoundedMultiply t, Show t, HasLegalValues t, Show (MixedMultEffortIndicator t tn), EffortIndicator (MixedMultEffortIndicator t tn), Show (ConvertEffortIndicator tn t), EffortIndicator (ConvertEffortIndicator tn t), Show (MultEffortIndicator t), EffortIndicator (MultEffortIndicator t), Show (NumOrd.MinmaxEffortIndicator t), EffortIndicator (NumOrd.MinmaxEffortIndicator t), Show (NumOrd.PartialCompareEffortIndicator t), EffortIndicator (NumOrd.PartialCompareEffortIndicator t) ) => t -> tn -> (NumOrd.PartialCompareEffortIndicator t, (MixedMultEffortIndicator t tn, (MultEffortIndicator t, ConvertEffortIndicator tn t, NumOrd.MinmaxEffortIndicator t))) -> (NumOrd.UniformlyOrderedSingleton t) -> tn -> Bool propMixedMultEqualsConvert sample sampleN initEffort (NumOrd.UniformlyOrderedSingleton d) n = equalRoundingUpDn "mixed multiplication by conversion" expr1Up expr1Dn expr2Up expr2Dn NumOrd.pLeqEff initEffort where expr1Up (effMMult,_) = let (*^|) = mixedMultUpEff effMMult in d *^| n expr1Dn (effMMult,_) = let (*.|) = mixedMultDnEff effMMult in d *.| n expr2Up (_,(effMult,effConv,effMinmax)) = let (*^) = multUpEff effMult in NumOrd.maxUpEff effMinmax (d *^ (fromJust $ convertUpEff effConv n)) (d *^ (fromJust $ convertDnEff effConv n)) expr2Dn (_,(effMult,effConv,effMinmax)) = let (*.) = multDnEff effMult in NumOrd.minDnEff effMinmax (d *. (fromJust $ convertUpEff effConv n)) (d *. (fromJust $ convertDnEff effConv n)) class RoundedMixedDivideEffort t tn where type MixedDivEffortIndicator t tn mixedDivDefaultEffort :: t -> tn -> MixedDivEffortIndicator t tn class (RoundedMixedDivideEffort t tn) => RoundedMixedDivide t tn where mixedDivUpEff :: MixedDivEffortIndicator t tn -> t -> tn -> t mixedDivDnEff :: MixedDivEffortIndicator t tn -> t -> tn -> t {- tools to easily make a RoundedMixedDivide instance via the composition of conversion and homogeneous addition -} type MixedDivEffortIndicatorByConversion t tn = (DivEffortIndicator t, ConvertEffortIndicator tn t, (NumOrd.MinmaxEffortIndicator t, NumOrd.PartialCompareEffortIndicator t)) mixedDivDefaultEffortByConversion d n = (addDefaultEffort d, convertDefaultEffort n d, (NumOrd.minmaxDefaultEffort d, NumOrd.pCompareDefaultEffort d)) mixedDivUpEffByConversion :: (Convertible tn t, RoundedDivide t, HasZero t, HasInfinities t, NumOrd.PartialComparison t, NumOrd.RoundedLattice t, Show tn) => (DivEffortIndicator t, ConvertEffortIndicator tn t, (NumOrd.MinmaxEffortIndicator t, NumOrd.PartialCompareEffortIndicator t)) -> t -> tn -> t mixedDivUpEffByConversion (effDiv, effConv, (effMinmax, effComp)) d n = let ?pCompareEffort = effComp in case (nDn >=? zero, nUp <=? zero) of (Just True, _) -> normalResult (_, Just True) -> normalResult _ -> plusInfinity -- b is too close to zero where normalResult = NumOrd.maxDnEff effMinmax -- we do not know the sign of a (divUpEff effDiv d nDn) (divUpEff effDiv d nUp) (nUp, nDn) = case (convertUpEff effConv n, convertDnEff effConv n) of (Just nUp, Just nDn) -> (nUp, nDn) _ -> throw $ AERNException $ "conversion failed during mixed division: n = " ++ show n mixedDivDnEffByConversion :: (Convertible tn t, RoundedDivide t, HasZero t, HasInfinities t, NumOrd.PartialComparison t, NumOrd.RoundedLattice t, Show tn) => (DivEffortIndicator t, ConvertEffortIndicator tn t, (NumOrd.MinmaxEffortIndicator t, NumOrd.PartialCompareEffortIndicator t)) -> t -> tn -> t mixedDivDnEffByConversion (effDiv, effConv, (effMinmax, effComp)) d n = let ?pCompareEffort = effComp in case (nDn >=? zero, nUp <=? zero) of (Just True, _) -> normalResult (_, Just True) -> normalResult _ -> minusInfinity -- b is too close to zero where normalResult = NumOrd.minDnEff effMinmax -- we do not know the sign of a (divDnEff effDiv d nDn) (divDnEff effDiv d nUp) (nUp, nDn) = case (convertUpEff effConv n, convertDnEff effConv n) of (Just nUp, Just nDn) -> (nUp, nDn) _ -> throw $ AERNException $ "conversion failed during mixed division: n = " ++ show n {- properties of mixed multiplication -} propMixedDivEqualsConvert :: (NumOrd.PartialComparison t, NumOrd.RoundedLattice t, Convertible tn t, RoundedMixedDivide t tn, RoundedDivide t, Show t, HasLegalValues t, HasZero t, Show (MixedDivEffortIndicator t tn), EffortIndicator (MixedDivEffortIndicator t tn), Show (ConvertEffortIndicator tn t), EffortIndicator (ConvertEffortIndicator tn t), Show (DivEffortIndicator t), EffortIndicator (DivEffortIndicator t), Show (NumOrd.MinmaxEffortIndicator t), EffortIndicator (NumOrd.MinmaxEffortIndicator t), Show (NumOrd.PartialCompareEffortIndicator t), EffortIndicator (NumOrd.PartialCompareEffortIndicator t) ) => t -> tn -> (NumOrd.PartialCompareEffortIndicator t, (MixedDivEffortIndicator t tn, (DivEffortIndicator t, ConvertEffortIndicator tn t, NumOrd.MinmaxEffortIndicator t))) -> (NumOrd.UniformlyOrderedSingleton t) -> tn -> Bool propMixedDivEqualsConvert sample sampleN initEffort@(effComp,(_,(_,effConv,_))) (NumOrd.UniformlyOrderedSingleton d) n = equalRoundingUpDn "mixed division by conversion" expr1Up expr1Dn expr2Up expr2Dn NumOrd.pLeqEff initEffort where expr1Up (effMDiv,_) = let (/^|) = mixedDivUpEff effMDiv in d /^| n expr1Dn (effMDiv,_) = let (/.|) = mixedDivDnEff effMDiv in d /.| n expr2Up (_,(effDiv,effConv,effMinmax)) = let (/^) = divUpEff effDiv in NumOrd.maxUpEff effMinmax (d /^ (fromJust $ convertUpEff effConv n)) (d /^ (fromJust $ convertDnEff effConv n)) expr2Dn (_,(effDiv,effConv,effMinmax)) = let (/.) = divDnEff effDiv in NumOrd.minDnEff effMinmax (d /. (fromJust $ convertUpEff effConv n)) (d /. (fromJust $ convertDnEff effConv n)) testsUpDnMixedFieldOps (name, sample) (nameN, sampleN) = testGroup (name ++ " with " ++ nameN ++ ": mixed up/dn rounded ops") $ [ testProperty "addition" (propMixedAddEqualsConvert sample sampleN) , testProperty "multiplication" (propMixedMultEqualsConvert sample sampleN) , testProperty "division" (propMixedDivEqualsConvert sample sampleN) ] class (RoundedMixedAddEffort t tn, RoundedMixedMultiplyEffort t tn) => RoundedMixedRingEffort t tn where type MixedRingOpsEffortIndicator t tn mixedRingOpsDefaultEffort :: t -> tn -> MixedRingOpsEffortIndicator t tn mxringEffortAdd :: t -> tn -> MixedRingOpsEffortIndicator t tn -> MixedAddEffortIndicator t tn mxringEffortMult :: t -> tn -> MixedRingOpsEffortIndicator t tn -> MixedMultEffortIndicator t tn class (RoundedMixedAdd t tn, RoundedMixedMultiply t tn, RoundedMixedRingEffort t tn) => RoundedMixedRing t tn class (RoundedMixedRingEffort t tn, RoundedMixedDivideEffort t tn) => RoundedMixedFieldEffort t tn where type MixedFieldOpsEffortIndicator t tn mixedFieldOpsDefaultEffort :: t -> tn -> MixedFieldOpsEffortIndicator t tn mxfldEffortAdd :: t -> tn -> MixedFieldOpsEffortIndicator t tn -> MixedAddEffortIndicator t tn mxfldEffortMult :: t -> tn -> MixedFieldOpsEffortIndicator t tn -> MixedMultEffortIndicator t tn mxfldEffortDiv :: t -> tn -> MixedFieldOpsEffortIndicator t tn -> MixedDivEffortIndicator t tn class (RoundedMixedRing t tn, RoundedMixedDivide t tn, RoundedMixedFieldEffort t tn) => RoundedMixedField t tn