numhask-0.7.1.0: A numeric class hierarchy.
Safe HaskellNone
LanguageHaskell2010

NumHask.Data.LogField

Description

A Field in the log domain.

LogField is adapted from logfloat

Synopsis

LogField

data LogField a Source #

A LogField is just a Field with a special interpretation. The LogField function is presented instead of the constructor, in order to ensure semantic conversion. At present the Show instance will convert back to the normal-domain, and hence will underflow at that point. This behavior may change in the future.

Because logField performs the semantic conversion, we can use operators which say what we *mean* rather than saying what we're actually doing to the underlying representation. That is, equivalences like the following are true[1] thanks to type-class overloading:

logField (p + q) == logField p + logField q
logField (p * q) == logField p * logField q

Performing operations in the log-domain is cheap, prevents underflow, and is otherwise very nice for dealing with miniscule probabilities. However, crossing into and out of the log-domain is expensive and should be avoided as much as possible. In particular, if you're doing a series of multiplications as in lp * LogField q * LogField r it's faster to do lp * LogField (q * r) if you're reasonably sure the normal-domain multiplication won't underflow; because that way you enter the log-domain only once, instead of twice. Also note that, for precision, if you're doing more than a few multiplications in the log-domain, you should use product rather than using (*) repeatedly.

Even more particularly, you should avoid addition whenever possible. Addition is provided because sometimes we need it, and the proper implementation is not immediately apparent. However, between two LogFields addition requires crossing the exp/log boundary twice; with a LogField and a Double it's three times, since the regular number needs to enter the log-domain first. This makes addition incredibly slow. Again, if you can parenthesize to do normal-domain operations first, do it!

1
That is, true up-to underflow and floating point fuzziness. Which is, of course, the whole point of this module.

Instances

Instances details
Functor LogField Source # 
Instance details

Defined in NumHask.Data.LogField

Methods

fmap :: (a -> b) -> LogField a -> LogField b #

(<$) :: a -> LogField b -> LogField a #

Foldable LogField Source # 
Instance details

Defined in NumHask.Data.LogField

Methods

fold :: Monoid m => LogField m -> m #

foldMap :: Monoid m => (a -> m) -> LogField a -> m #

foldMap' :: Monoid m => (a -> m) -> LogField a -> m #

foldr :: (a -> b -> b) -> b -> LogField a -> b #

foldr' :: (a -> b -> b) -> b -> LogField a -> b #

foldl :: (b -> a -> b) -> b -> LogField a -> b #

foldl' :: (b -> a -> b) -> b -> LogField a -> b #

foldr1 :: (a -> a -> a) -> LogField a -> a #

foldl1 :: (a -> a -> a) -> LogField a -> a #

toList :: LogField a -> [a] #

null :: LogField a -> Bool #

length :: LogField a -> Int #

elem :: Eq a => a -> LogField a -> Bool #

maximum :: Ord a => LogField a -> a #

minimum :: Ord a => LogField a -> a #

sum :: Num a => LogField a -> a #

product :: Num a => LogField a -> a #

Traversable LogField Source # 
Instance details

Defined in NumHask.Data.LogField

Methods

traverse :: Applicative f => (a -> f b) -> LogField a -> f (LogField b) #

sequenceA :: Applicative f => LogField (f a) -> f (LogField a) #

mapM :: Monad m => (a -> m b) -> LogField a -> m (LogField b) #

sequence :: Monad m => LogField (m a) -> m (LogField a) #

Eq a => Eq (LogField a) Source # 
Instance details

Defined in NumHask.Data.LogField

Methods

(==) :: LogField a -> LogField a -> Bool #

(/=) :: LogField a -> LogField a -> Bool #

Data a => Data (LogField a) Source # 
Instance details

Defined in NumHask.Data.LogField

Methods

gfoldl :: (forall d b. Data d => c (d -> b) -> d -> c b) -> (forall g. g -> c g) -> LogField a -> c (LogField a) #

gunfold :: (forall b r. Data b => c (b -> r) -> c r) -> (forall r. r -> c r) -> Constr -> c (LogField a) #

toConstr :: LogField a -> Constr #

dataTypeOf :: LogField a -> DataType #

dataCast1 :: Typeable t => (forall d. Data d => c (t d)) -> Maybe (c (LogField a)) #

dataCast2 :: Typeable t => (forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c (LogField a)) #

gmapT :: (forall b. Data b => b -> b) -> LogField a -> LogField a #

gmapQl :: (r -> r' -> r) -> r -> (forall d. Data d => d -> r') -> LogField a -> r #

gmapQr :: forall r r'. (r' -> r -> r) -> r -> (forall d. Data d => d -> r') -> LogField a -> r #

gmapQ :: (forall d. Data d => d -> u) -> LogField a -> [u] #

gmapQi :: Int -> (forall d. Data d => d -> u) -> LogField a -> u #

gmapM :: Monad m => (forall d. Data d => d -> m d) -> LogField a -> m (LogField a) #

gmapMp :: MonadPlus m => (forall d. Data d => d -> m d) -> LogField a -> m (LogField a) #

gmapMo :: MonadPlus m => (forall d. Data d => d -> m d) -> LogField a -> m (LogField a) #

Ord a => Ord (LogField a) Source # 
Instance details

Defined in NumHask.Data.LogField

Methods

compare :: LogField a -> LogField a -> Ordering #

(<) :: LogField a -> LogField a -> Bool #

(<=) :: LogField a -> LogField a -> Bool #

(>) :: LogField a -> LogField a -> Bool #

(>=) :: LogField a -> LogField a -> Bool #

max :: LogField a -> LogField a -> LogField a #

min :: LogField a -> LogField a -> LogField a #

Read a => Read (LogField a) Source # 
Instance details

Defined in NumHask.Data.LogField

(ExpField a, Show a) => Show (LogField a) Source # 
Instance details

Defined in NumHask.Data.LogField

Methods

showsPrec :: Int -> LogField a -> ShowS #

show :: LogField a -> String #

showList :: [LogField a] -> ShowS #

Generic (LogField a) Source # 
Instance details

Defined in NumHask.Data.LogField

Associated Types

type Rep (LogField a) :: Type -> Type #

Methods

from :: LogField a -> Rep (LogField a) x #

to :: Rep (LogField a) x -> LogField a #

(ExpField a, Ord a, LowerBoundedField a, UpperBoundedField a) => Subtractive (LogField a) Source # 
Instance details

Defined in NumHask.Data.LogField

(ExpField a, LowerBoundedField a, Ord a) => Additive (LogField a) Source # 
Instance details

Defined in NumHask.Data.LogField

(LowerBoundedField a, Eq a) => Divisive (LogField a) Source # 
Instance details

Defined in NumHask.Data.LogField

(LowerBoundedField a, Eq a) => Multiplicative (LogField a) Source # 
Instance details

Defined in NumHask.Data.LogField

Methods

(*) :: LogField a -> LogField a -> LogField a Source #

one :: LogField a Source #

(Ord a, LowerBoundedField a, ExpField a) => Distributive (LogField a) Source # 
Instance details

Defined in NumHask.Data.LogField

(Ord a, ExpField a, LowerBoundedField a, UpperBoundedField a) => LowerBoundedField (LogField a) Source # 
Instance details

Defined in NumHask.Data.LogField

(Ord a, ExpField a, LowerBoundedField a, UpperBoundedField a) => UpperBoundedField (LogField a) Source # 
Instance details

Defined in NumHask.Data.LogField

(Field (LogField a), ExpField a, LowerBoundedField a, Ord a) => ExpField (LogField a) Source # 
Instance details

Defined in NumHask.Data.LogField

(Ord a, ExpField a, LowerBoundedField a, UpperBoundedField a) => Field (LogField a) Source # 
Instance details

Defined in NumHask.Data.LogField

Ord a => MeetSemiLattice (LogField a) Source # 
Instance details

Defined in NumHask.Data.LogField

Methods

(/\) :: LogField a -> LogField a -> LogField a Source #

Ord a => JoinSemiLattice (LogField a) Source # 
Instance details

Defined in NumHask.Data.LogField

Methods

(\/) :: LogField a -> LogField a -> LogField a Source #

(Epsilon a, ExpField a, LowerBoundedField a, UpperBoundedField a, Ord a) => Epsilon (LogField a) Source # 
Instance details

Defined in NumHask.Data.LogField

(Ord a, LowerBoundedField a, UpperBoundedField a, ExpField a) => Signed (LogField a) Source # 
Instance details

Defined in NumHask.Data.LogField

Generic1 LogField Source # 
Instance details

Defined in NumHask.Data.LogField

Associated Types

type Rep1 LogField :: k -> Type #

Methods

from1 :: forall (a :: k). LogField a -> Rep1 LogField a #

to1 :: forall (a :: k). Rep1 LogField a -> LogField a #

(FromIntegral a b, ExpField a) => FromIntegral (LogField a) b Source # 
Instance details

Defined in NumHask.Data.LogField

Methods

fromIntegral :: b -> LogField a Source #

(ToIntegral a b, ExpField a) => ToIntegral (LogField a) b Source # 
Instance details

Defined in NumHask.Data.LogField

Methods

toIntegral :: LogField a -> b Source #

(FromRatio a b, ExpField a) => FromRatio (LogField a) b Source # 
Instance details

Defined in NumHask.Data.LogField

Methods

fromRatio :: Ratio b -> LogField a Source #

(ToRatio a b, ExpField a) => ToRatio (LogField a) b Source # 
Instance details

Defined in NumHask.Data.LogField

Methods

toRatio :: LogField a -> Ratio b Source #

type Rep (LogField a) Source # 
Instance details

Defined in NumHask.Data.LogField

type Rep (LogField a) = D1 ('MetaData "LogField" "NumHask.Data.LogField" "numhask-0.7.1.0-L0knaGsPb6PJAGlPoK4bjY" 'True) (C1 ('MetaCons "LogField" 'PrefixI 'False) (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 a)))
type Rep1 LogField Source # 
Instance details

Defined in NumHask.Data.LogField

type Rep1 LogField = D1 ('MetaData "LogField" "NumHask.Data.LogField" "numhask-0.7.1.0-L0knaGsPb6PJAGlPoK4bjY" 'True) (C1 ('MetaCons "LogField" 'PrefixI 'False) (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) Par1))

logField :: ExpField a => a -> LogField a Source #

Constructor which does semantic conversion from normal-domain to log-domain. Throws errors on negative and NaN inputs. If p is non-negative, then following equivalence holds:

logField p == logToLogField (log p)

fromLogField :: ExpField a => LogField a -> a Source #

Semantically convert our log-domain value back into the normal-domain. Beware of overflow/underflow. The following equivalence holds (without qualification):

fromLogField == exp . logFromLogField

Isomorphism to log-domain

logToLogField :: a -> LogField a Source #

Constructor which assumes the argument is already in the log-domain.

logFromLogField :: LogField a -> a Source #

Return the log-domain value itself without conversion.

Additional operations

accurateSum :: (ExpField a, Foldable f, Ord a) => f (LogField a) -> LogField a Source #

O(n). Compute the sum of a finite list of LogFields, being careful to avoid underflow issues. That is, the following equivalence holds (modulo underflow and all that):

LogField . accurateSum == accurateSum . map LogField

N.B., this function requires two passes over the input. Thus, it is not amenable to list fusion, and hence will use a lot of memory when summing long lists.

accurateProduct :: (ExpField a, Foldable f) => f (LogField a) -> LogField a Source #

O(n). Compute the product of a finite list of LogFields, being careful to avoid numerical error due to loss of precision. That is, the following equivalence holds (modulo underflow and all that):

LogField . accurateProduct == accurateProduct . map LogField

pow :: (ExpField a, LowerBoundedField a, Ord a) => LogField a -> a -> LogField a infixr 8 Source #

O(1). Compute powers in the log-domain; that is, the following equivalence holds (modulo underflow and all that):

LogField (p ** m) == LogField p `pow` m