-- Hoogle documentation, generated by Haddock
-- See Hoogle, http://www.haskell.org/hoogle/
-- | Log-domain floating point numbers
--
-- This module presents a class for storing numbers in the log-domain.
-- The main reason for doing this is to prevent underflow when
-- multiplying many probabilities as is done in Hidden Markov Models. It
-- is also helpful for preventing overflow.
@package logfloat
@version 0.8.4
-- | This module presents a type class for numbers which have
-- representations for transfinite values. The idea originated from the
-- IEEE-754 floating-point special values, used by
-- Data.Number.LogFloat. However not all Fractional types
-- necessarily support transfinite values. In particular, Ratio
-- types including Rational do not have portable representations.
--
-- For the Glasgow compiler (GHC 6.8.2), GHC.Real defines
-- 1%0 and 0%0 as representations for infinity
-- and notANumber, but most operations on them will raise
-- exceptions. If toRational is used on an infinite floating
-- value, the result is a rational with a numerator sufficiently large
-- that it will overflow when converted back to a Double. If
-- used on NaN, the result would convert back as negativeInfinity.
--
-- Hugs (September 2006) stays closer to the haskell98 spec and offers no
-- way of constructing those values, raising arithmetic overflow errors
-- if attempted.
module Data.Number.Transfinite
-- | Many numbers are not Bounded yet, even though they can
-- represent arbitrarily large values, they are not necessarily able to
-- represent transfinite values such as infinity itself. This class is
-- for types which are capable of representing such values. Notably, this
-- class does not require the type to be Fractional nor
-- Floating since integral types could also have representations
-- for transfinite values.
--
-- In particular, this class extends the Ord projection to have a
-- maximum value infinity and a minimum value
-- negativeInfinity, as well as an exceptional value
-- notANumber. All the natural laws regarding infinity
-- and negativeInfinity should pertain. Additionally,
-- infinity - infinity should return notANumber (as
-- should 0/0 and infinity/infinity if the type is
-- Fractional). Any operations on notANumber will also
-- return notANumber, and any equality or ordering comparison on
-- notANumber must return False.
--
-- Minimum complete definition is infinity, isInfinite,
-- and isNaN.
class (Num a, Ord a) => Transfinite a
infinity :: (Transfinite a) => a
negativeInfinity :: (Transfinite a) => a
notANumber :: (Transfinite a) => a
isInfinite :: (Transfinite a) => a -> Bool
isNaN :: (Transfinite a) => a -> Bool
instance Transfinite Float
instance Transfinite Double
-- | This module presents a type for storing numbers in the log-domain. The
-- main reason for doing this is to prevent underflow when multiplying
-- many small probabilities as is done in Hidden Markov Models and other
-- statistical models often used for natural language processing. The
-- log-domain also helps prevent overflow when multiplying many large
-- numbers. In rare cases it can speed up numerical computation (since
-- addition is faster than multiplication, though logarithms are
-- exceptionally slow), but the primary goal is to improve accuracy of
-- results. A secondary goal has been to maximize efficiency since these
-- computations are frequently done within a O(n^3) loop.
--
-- The LogFloat of this module is restricted to non-negative
-- numbers for efficiency's sake, see the forthcoming
-- Data.Number.LogFloat.Signed for doing signed log-domain
-- calculations.
module Data.Number.LogFloat
-- | Since the normal log throws an error on zero, we have to
-- redefine it in order for things to work right. Arguing from limits we
-- can see that log 0 == negativeInfinity.
--
-- In order to improve portability, the Transfinite class is
-- required to indicate that the Floating type does in fact have a
-- representation for negative infinity. Both native Floating
-- types (Double and Float) are supported. If you define
-- your own instance of Transfinite, verify the above equation
-- holds for your 0 and negativeInfinity. If it
-- doesn't, then you should avoid importing our log and will
-- probably want converters to handle the discrepancy when dealing with
-- LogFloats.
log :: (Floating a, Transfinite a) => a -> a
-- | The most generic numeric converter I can come up with. All the
-- built-in numeric types are Real, though Int and
-- Integer aren't Fractional. Beware that converting
-- transfinite values into Ratio types is error-prone and
-- non-portable, as discussed in Data.Number.Transfinite.
toFractional :: (Real a, Fractional b) => a -> b
-- | A LogFloat is just a Double with a special
-- interpretation. The logFloat 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
-- so will underflow at that point. This behavior may change in the
-- future.
--
-- 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 * logFloat q * logFloat
-- r it's faster to do lp * logFloat (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.
--
-- Even more particularly, you should avoid addition whenever
-- possible. Addition is provided because it's necessary at times and the
-- proper implementation is not immediately transparent. However, between
-- two LogFloats addition requires crossing the exp/log boundary
-- twice; with a LogFloat and a regular number 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
-- plain operations first, do it!
data LogFloat
-- | A constructor which does semantic conversion from normal-domain to
-- log-domain.
logFloat :: (Real a) => a -> LogFloat
-- | Constructor which assumes the argument is already in the log-domain.
logToLogFloat :: (Real a) => a -> LogFloat
-- | Return our log-domain value back into normal-domain. Beware of
-- overflow/underflow.
fromLogFloat :: (Fractional a, Transfinite a) => LogFloat -> a
-- | Return the log-domain value itself without costly conversion
logFromLogFloat :: (Fractional a, Transfinite a) => LogFloat -> a
instance Eq LogFloat
instance Ord LogFloat
instance Real LogFloat
instance Fractional LogFloat
instance Num LogFloat
instance Show LogFloat