extended-reals (empty) → 0.1.0.0
raw patch · 6 files changed
+409/−0 lines, 6 filesdep +HUnitdep +QuickCheckdep +basesetup-changed
Dependencies added: HUnit, QuickCheck, base, deepseq, extended-reals, hashable, test-framework, test-framework-hunit, test-framework-quickcheck2, test-framework-th
Files
- .travis.yml +56/−0
- LICENSE +30/−0
- Setup.hs +2/−0
- extended-reals.cabal +37/−0
- src/Data/ExtendedReal.hs +130/−0
- test/TestExtendedReal.hs +154/−0
+ .travis.yml view
@@ -0,0 +1,56 @@+# NB: don't set `language: haskell` here++# The following enables several GHC versions to be tested; often it's enough to test only against the last release in a major GHC version. Feel free to omit lines listings versions you don't need/want testing for.+env:+# - GHCVER=6.12.3+# - GHCVER=7.0.1+# - GHCVER=7.0.2+# - GHCVER=7.0.3+# - GHCVER=7.0.4+# - GHCVER=7.2.1+# - GHCVER=7.2.2+# - GHCVER=7.4.1+# - GHCVER=7.4.2+# - GHCVER=7.6.1+# - GHCVER=7.6.2+ - GHCVER=7.6.3+# - GHCVER=7.8.1 # see note about Alex/Happy+# - GHCVER=7.8.2 # see note about Alex/Happy+ - GHCVER=7.8.3 # see note about Alex/Happy+# - GHCVER=head # see section about GHC HEAD snapshots++# Note: the distinction between `before_install` and `install` is not important.+before_install:+ - travis_retry sudo add-apt-repository -y ppa:hvr/ghc+ - travis_retry sudo apt-get update+ - travis_retry sudo apt-get install cabal-install-1.18 ghc-$GHCVER # see note about happy/alex+ - export PATH=/opt/ghc/$GHCVER/bin:/opt/cabal/1.18/bin:$PATH+ - |+ if [ $GHCVER = "head" ] || [ ${GHCVER%.*} = "7.8" ]; then+ travis_retry sudo apt-get install happy-1.19.3 alex-3.1.3+ export PATH=/opt/alex/3.1.3/bin:/opt/happy/1.19.3/bin:$PATH+ else+ travis_retry sudo apt-get install happy alex+ fi++install:+ - cabal update+ - cabal install --only-dependencies --enable-tests -v2 # -v2 provides useful information for debugging++# Here starts the actual work to be performed for the package under test; any command which exits with a non-zero exit code causes the build to fail.+script:+ - cabal configure --enable-tests -v2 # -v2 provides useful information for debugging+ - cabal build # this builds all libraries and executables (including tests/benchmarks)+ - cabal test+ - cabal check+ - cabal sdist # tests that a source-distribution can be generated++# The following scriptlet checks that the resulting source distribution can be built & installed+ - export SRC_TGZ=$(cabal-1.18 info . | awk '{print $2 ".tar.gz";exit}') ;+ cd dist/;+ if [ -f "$SRC_TGZ" ]; then+ cabal install "$SRC_TGZ";+ else+ echo "expected '$SRC_TGZ' not found";+ exit 1;+ fi
+ LICENSE view
@@ -0,0 +1,30 @@+Copyright (c) 2014, Masahiro Sakai++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++ * Redistributions of source code must retain the above copyright+ notice, this list of conditions and the following disclaimer.++ * Redistributions in binary form must reproduce the above+ copyright notice, this list of conditions and the following+ disclaimer in the documentation and/or other materials provided+ with the distribution.++ * Neither the name of Masahiro Sakai nor the names of other+ contributors may be used to endorse or promote products derived+ from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ extended-reals.cabal view
@@ -0,0 +1,37 @@+name: extended-reals+version: 0.1.0.0+synopsis: Extension of real numbers with positive/negative infinities+description:+ Extension of real numbers with positive/negative infinities (±∞).+ It is useful for describing various limiting behaviors in mathematics.+homepage: https://github.com/msakai/extended-reals/+license: BSD3+license-file: LICENSE+author: Masahiro Sakai+maintainer: masahiro.sakai@gmail.com+category: Math+build-type: Simple+extra-source-files: .travis.yml+cabal-version: >=1.10+bug-reports: https://github.com/msakai/extended-reals/issues++source-repository head+ type: git+ location: git://github.com/msakai/extended-reals.git++library+ exposed-modules: Data.ExtendedReal+ other-extensions: DeriveDataTypeable+ build-depends: base >=4 && <5, deepseq >=1.3 && <1.4, hashable >=1.2 && <1.3+ hs-source-dirs: src+ default-language: Haskell2010++Test-suite TestExtendedReal+ Type: exitcode-stdio-1.0+ HS-Source-Dirs: test+ Main-is: TestExtendedReal.hs+ Build-depends: base, HUnit >=1.2 && <1.3, QuickCheck >=2.6 && <2.7, test-framework >=0.8 && <0.9, test-framework-th >=0.2 && <0.3, test-framework-hunit >=0.3 && <0.4, test-framework-quickcheck2 >=0.3 && <0.4, extended-reals+ Default-Language: Haskell2010+ Other-Extensions:+ TemplateHaskell+ ScopedTypeVariables
+ src/Data/ExtendedReal.hs view
@@ -0,0 +1,130 @@+{-# OPTIONS_GHC -Wall #-}+{-# LANGUAGE DeriveDataTypeable #-}+-----------------------------------------------------------------------------+-- |+-- Module : Data.ExtendedReal+-- Copyright : (c) Masahiro Sakai 2014+-- License : BSD-style+-- +-- Maintainer : masahiro.sakai@gmail.com+-- Stability : provisional+-- Portability : non-portable (DeriveDataTypeable)+--+-- Extension of real numbers with positive/negative infinities (±∞).+-- It is useful for describing various limiting behaviors in mathematics.+--+-- Remarks:+--+-- * @∞ - ∞@ is left undefined as usual,+-- but we define @0 × ∞ = 0 × -∞ = 0@ by following the convention of+-- probability or measure theory.+--+-- References:+--+-- * Wikipedia contributors, "Extended real number line," Wikipedia,+-- The Free Encyclopedia, https://en.wikipedia.org/wiki/Extended_real_number_line+-- (accessed September 1, 2014).+--+-----------------------------------------------------------------------------+module Data.ExtendedReal+ ( Extended (..)+ , isFinite+ , isInfinite+ ) where++import Prelude hiding (isInfinite)+import Control.DeepSeq+import Data.Data+import Data.Hashable+import Data.Typeable++-- | @Extended r@ is an extension of /r/ with positive/negative infinity (±∞).+data Extended r+ = NegInf -- ^ negative infinity (-∞)+ | Finite !r -- ^ finite value+ | PosInf -- ^ positive infinity (+∞)+ deriving (Ord, Eq, Show, Read, Typeable, Data)++instance Bounded (Extended r) where+ minBound = NegInf+ maxBound = PosInf++instance Functor Extended where+ fmap _ NegInf = NegInf+ fmap f (Finite x) = Finite (f x)+ fmap _ PosInf = PosInf++instance NFData r => NFData (Extended r) where+ rnf (Finite x) = rnf x+ rnf _ = ()++instance Hashable r => Hashable (Extended r) where+ hashWithSalt s NegInf = s `hashWithSalt` (0::Int)+ hashWithSalt s (Finite x) = s `hashWithSalt` (1::Int) `hashWithSalt` x+ hashWithSalt s PosInf = s `hashWithSalt` (2::Int)++-- | @isFinite x = not (isInfinite x)@.+isFinite :: Extended r -> Bool+isFinite (Finite _) = True+isFinite _ = False++-- | @isInfinite x@ returns @True@ iff @x@ is @PosInf@ or @NegInf@.+isInfinite :: Extended r -> Bool+isInfinite = not . isFinite++-- | Note that @Extended r@ is /not/ a field, nor a ring.+-- +-- @PosInf + NegInf@ is left undefined as usual,+-- but we define @0 * PosInf = 0 * NegInf = 0@ by following the convention of probability or measure theory.+instance (Num r, Ord r) => Num (Extended r) where+ Finite a + Finite b = Finite (a+b)+ PosInf + NegInf = error "PosInf + NegInf is undefined"+ NegInf + PosInf = error "NegInf + PosInf is undefined"+ PosInf + _ = PosInf+ _ + PosInf = PosInf+ NegInf + _ = NegInf+ _ + NegInf = NegInf++ Finite x1 * e = scale x1 e+ e * Finite x2 = scale x2 e+ PosInf * PosInf = PosInf+ PosInf * NegInf = NegInf+ NegInf * PosInf = NegInf+ NegInf * NegInf = PosInf++ negate NegInf = PosInf+ negate (Finite x) = Finite (negate x)+ negate PosInf = NegInf++ abs NegInf = PosInf+ abs (Finite x) = Finite (abs x)+ abs PosInf = PosInf++ signum NegInf = Finite (-1)+ signum (Finite x) = Finite (signum x)+ signum PosInf = Finite 1++ fromInteger = Finite . fromInteger ++-- | Note that @Extended r@ is /not/ a field, nor a ring.+instance (Fractional r, Ord r) => Fractional (Extended r) where+ recip (Finite x) = Finite (1/x)+ recip _ = Finite 0++ fromRational = Finite . fromRational++-- Note that we define @0 * PosInf = 0 * NegInf = 0@ by the convention of probability or measure theory.+scale :: (Num r, Ord r) => r -> Extended r -> Extended r+scale a e = seq e $+ case a `compare` 0 of+ EQ -> Finite 0+ GT ->+ case e of+ NegInf -> NegInf+ Finite b -> Finite (a*b)+ PosInf -> PosInf+ LT ->+ case e of+ NegInf -> PosInf+ Finite b -> Finite (a*b)+ PosInf -> NegInf
+ test/TestExtendedReal.hs view
@@ -0,0 +1,154 @@+{-# OPTIONS_GHC -Wall #-}+{-# LANGUAGE TemplateHaskell, ScopedTypeVariables #-}++import Prelude hiding (isInfinite)+import Control.Exception (SomeException, evaluate, try)+import Control.Monad+import Data.Maybe+import System.IO.Unsafe (unsafePerformIO)+import Test.HUnit hiding (Test)+import Test.QuickCheck+import Test.Framework.TH+import Test.Framework.Providers.HUnit+import Test.Framework.Providers.QuickCheck2++import Data.ExtendedReal++-- ----------------------------------------------------------------------++instance Arbitrary r => Arbitrary (Extended r) where+ arbitrary = + oneof+ [ return NegInf+ , return PosInf+ , liftM Finite arbitrary+ ]++eval :: a -> Maybe a+eval a = unsafePerformIO $ do+ ret <- try (evaluate a)+ case ret of+ Left (_::SomeException) -> return Nothing+ Right b -> return $ Just b++isDefined :: a -> Bool+isDefined = isJust . eval++-- ----------------------------------------------------------------------++prop_add_comm :: Property+prop_add_comm =+ forAll arbitrary $ \(a :: Extended Rational) ->+ forAll arbitrary $ \b ->+ eval (a + b) == eval (b + a)++prop_add_assoc :: Property+prop_add_assoc =+ forAll arbitrary $ \(a :: Extended Rational) ->+ forAll arbitrary $ \b ->+ forAll arbitrary $ \c ->+ eval (a + (b + c)) == eval ((a + b) + c)++prop_add_unit :: Property+prop_add_unit =+ forAll arbitrary $ \(a :: Extended Rational) ->+ 0 + a == a++prop_add_monotone :: Property+prop_add_monotone =+ forAll arbitrary $ \(a :: Extended Rational) ->+ forAll arbitrary $ \b ->+ forAll arbitrary $ \c ->+ a <= b && isDefined (a+c) && isDefined (b+c)+ ==> a+c <= b+c++prop_mult_comm :: Property+prop_mult_comm =+ forAll arbitrary $ \(a :: Extended Rational) ->+ forAll arbitrary $ \b ->+ a * b == b * a++-- PosInf + NegInf is left undefined+case_add_PosInf_NegInf :: IO ()+case_add_PosInf_NegInf =+ eval (PosInf + NegInf :: Extended Rational) @?= Nothing++prop_mult_assoc :: Property+prop_mult_assoc =+ forAll arbitrary $ \(a :: Extended Rational) ->+ forAll arbitrary $ \b ->+ forAll arbitrary $ \c ->+ a * (b * c) == (a * b) * c++prop_mult_unit :: Property+prop_mult_unit =+ forAll arbitrary $ \(a :: Extended Rational) ->+ 1 * a == a++prop_mult_dist :: Property+prop_mult_dist =+ forAll arbitrary $ \(a :: Extended Rational) ->+ forAll arbitrary $ \b ->+ forAll arbitrary $ \c ->+ isDefined (a * (b + c)) && isDefined (a * b + a * c)+ ==> eval (a * (b + c)) == eval (a * b + a * c)++prop_mult_zero :: Property+prop_mult_zero = + forAll arbitrary $ \(a :: Extended Rational) ->+ 0 * a == 0++prop_mult_monotone :: Property+prop_mult_monotone =+ forAll arbitrary $ \(a :: Extended Rational) ->+ forAll arbitrary $ \b ->+ forAll arbitrary $ \c ->+ a <= b && c > 0 && isDefined (a*c) && isDefined (b*c)+ ==> a*c <= b*c++-- We define 0 * PosInf = 0+case_mult_zero_PosInf :: IO ()+case_mult_zero_PosInf =+ 0 * PosInf @?= (0 :: Extended Rational)++-- We define 0 * NegInf = 0+case_mult_zero_NegInf :: IO ()+case_mult_zero_NegInf =+ 0 * NegInf @?= (0 :: Extended Rational)++prop_negate_inverse :: Property+prop_negate_inverse = + forAll arbitrary $ \(a :: Extended Rational) ->+ negate (negate a) == a++prop_signum_abs :: Property+prop_signum_abs =+ forAll arbitrary $ \(a :: Extended Rational) ->+ signum a * abs a == a++prop_recip_inverse :: Property+prop_recip_inverse =+ forAll arbitrary $ \(a :: Extended Rational) ->+ isFinite a && a /= 0 ==> recip (recip a) == a++case_recip_PosInf :: IO ()+case_recip_PosInf = recip PosInf @?= (0 :: Extended Rational)++case_recip_NegInf :: IO ()+case_recip_NegInf = recip NegInf @?= (0 :: Extended Rational)++prop_NegInf_smallest :: Property+prop_NegInf_smallest =+ forAll arbitrary $ \(a :: Extended Rational) ->+ NegInf <= a++prop_PosInf_largest :: Property+prop_PosInf_largest =+ forAll arbitrary $ \(a :: Extended Rational) ->+ a <= PosInf++-- ----------------------------------------------------------------------+-- Test harness++main :: IO ()+main = $(defaultMainGenerator)