[Agda] summing rationals

Sergei Meshveliani mechvel at botik.ru
Sat Jun 24 21:06:11 CEST 2017


Dear all,

Consider the following performance test for rational arithmetic.
Call this test call "Harmonic":

  f n =  sum [1/k | k <- [1 .. n]]   for n : Nat, 1/k : Rational,
                                     
  sum = foldr _+_ 0    where _+_ = fraction addition

  test n =  let fn = f n
            in  fn - fn

  Read from file   n = 100, 1000, 2000, 100.000 ...,

  print  (test n)  and check time. 

(fn - fn)  is applied here in order to avoid printing large values.


  --------------------------- Haskell code -------
  import Data.Ratio ((%))

  f :: Integer -> Rational     -- :: Ratio Integer
  f n =
      sum [1 % k | k <- [1 .. n]]
  -------------------------------------------------


I compare the three libraries:

  (GHC) GHC  (Glasgow Haskell 7.10.2),

  (D)   DoCon-2.12  written in Haskell, running under GHC,

  (DA)  DoCon-A 2.00-pre   written in Agda, 
                           running under Agda 2.5.2 -like.

(D) and (DA) keep fractions with numerator and denominator mutually
coprime, and cancel fractions most eagerly by gcd.

(GHC)  does not cancel by gcd so eagerly.

The performance comparison on Harmonic is:
                                       
                (D) >> (GHC) > (DA).

(D) takes  n = 200.000  easily, while GHC "hangs" on 20.000
    -- for a 3 GHz machine.

(GHC) is considerably faster (DA) 
      (DA hangs for long on 4000).

The method in (DA) is the same as (D). 
gcd is almost as fast as GHC.gcd, this has been tested.
Division (with remainder) is via  dimMod  of Agda-prelude, it is fast.

And I wonder why (DA) is so slow.
(DA) carries all the needed proofs (for coprimality, and such).
But I hope, this does not effect performance any essentially.

Can anybody provide the code for testing Harmonic for  Rational numbers
in  agda-prelude ?

The (DA) test for (Fraction Integer) is like this:

------------------------------------------------------------------------
...
open Fraction.F0 Int1.integralRing-with∣? Int1.gcdRing using
                                 (Fraction; fraction; fraction-showInst)
open Fraction.F1 Int1.integralRing-with∣? Int1.gcdRing using (frRingoid)
open Ringoid frRingoid using (_-_)
open Fraction

inv-n :  ℕ → Fraction              -- \n → 1/(1+n)        
inv-n n =
        fraction (+ 1) (+ (suc n)) +suc≢+0

f : ℕ → Fraction    -- sum [1/n | n <- [1 .. n+1]]                
f n =
    sum frRingoid (map inv-n (natSegment 0 n))

main : IO Unit
main = (readFiniteFile "data.txt") >>= putStrLn ∘ toCostring ∘ g
  where
  g : String -> String
  g str =
    -- n  is first read from file  data.txt
                       
    concatStr
    ("n = "                 ∷  showNat n                 ∷ ",   " ∷
     "num (f n - f n) =  "  ∷  showInt (num (fn - fn))   ∷ "\n\n"   
     ∷ []
    )
    where
    n  = stringToNat $ filterStr decimalDigit? str
    fn = f n
-------------------------------------------------------------------------


So far, I do not find the performance bottleneck in (DA).

Thanks,

------
Sergei





More information about the Agda mailing list