Hi Eric, Thanks for taking a look.
On my computer (mac) your vector version is 3 times faster than the hash one: cpu time: 189 real time: 189 gc time: 3 cpu time: 53 real time: 53 gc time: 0 cpu time: 186 real time: 185 gc time: 3 cpu time: 58 real time: 58 gc time: 0 cpu time: 199 real time: 204 gc time: 2 cpu time: 56 real time: 56 gc time: 0 cpu time: 200 real time: 205 gc time: 3 cpu time: 58 real time: 57 gc time: 0 cpu time: 181 real time: 180 gc time: 2 cpu time: 64 real time: 64 gc time: 0 #t /Jens Axel 2014-06-28 18:10 GMT+02:00 Eric Dobson <eric.n.dob...@gmail.com>: > I took a look and for a while nothing I did sped it up, (likely > already racket was doing the optimizations I was doing by hand). But I > got a factor of 4 speed up on the vector code over the hash code by > not checking for exact 0, but instead using #f as the sentinal value. > Growing the vector by a a factor of 2 had some improvement as well but > didn't get the vector code faster than the hash code. > > https://gist.github.com/shekari/3bccee6e0d5948181f1a > > On Sat, Jun 28, 2014 at 8:43 AM, Jos Koot <jos.k...@gmail.com> wrote: >> When calling partitions once only the vector grows once only. Another case >> is when partitions is called many times with increasing argument. In that >> case the vector has to be copied every time. Therefore I would prefer the >> mutable hash. >> >> I have thought of combining the two seperate loops for negative and positive >> k into one loop, but as it is not certain that the loops have the same >> length, this complicates the loop with an extra if-clause cq cond-clause. >> >> Nevertheless, I think the main gain is obtained by using a recurrent formula >> for the computation of >> (- n (* k (add1 (* 3 k)))) and >> (- n (* k (sub1 (* 3 k)))) and >> more importantly avoiding to compute >> (/ (+ 1.0 (flsqrt (+ 1.0 (* 24.0 n)))) 6.0) >> for every instance the partitions count has not yet been memorized. >> It where the inexact operations that made me think. >> >> Another thing that could be tried is to sepatare both loops for even and odd >> k such as to avoid the test on the partity of k. I did not (yet) try that. >> This would lead to a total of 4 loops. >> >> Anyway, code should be readable and fast (in that order). Therefore >> complicating the code much for a slight gain of speed may be the wrong thing >> to do. MHO >> >> Jos >> >> >>> -----Original Message----- >>> From: jensaxelsoega...@gmail.com >>> [mailto:jensaxelsoega...@gmail.com] On Behalf Of Jens Axel Søgaard >>> Sent: sábado, 28 de junio de 2014 16:51 >>> To: Neil Toronto >>> Cc: Jos Koot; Racket Users List >>> Subject: Re: [racket] FW: q about code for partitions >>> >>> The vector grows only once, so that's not it. >>> >>> Below is a version where vector-ref! was removed. >>> This brings the timings closer to each other. >>> It seems that the hash version still is slightly faster though. >>> >>> Is there anything else that can be improved? >>> >>> #lang typed/racket/base >>> (provide partitions reset-partitions-cache) >>> (require math/private/number-theory/types) >>> >>> ;;; Partitions are computed using Euler's algorithm: >>> >>> ; k k(3k+1) k(3k-1) >>> ; p(n) = sum (-1) [ p( n - --------- ) + p( n - --------- ) ] >>> ; k>=1 2 2 >>> >>> ; http://en.wikipedia.org/wiki/Partition_(number_theory) >>> >>> (define cache-size 1) >>> (: cache (Vectorof Integer)) >>> (define cache (make-vector cache-size 0)) >>> (vector-set! cache 0 1) >>> >>> (: reset-partitions-cache : -> Void) >>> (define (reset-partitions-cache) >>> (set! cache-size 1) >>> (make-vector cache-size 0) >>> (set! cache (make-vector cache-size 0)) >>> (vector-set! cache 0 1)) >>> >>> (: grow-cache : Natural -> Void) >>> (define (grow-cache n) >>> (cond [(> cache-size n) (void)] >>> [else (define n+1 (+ n 1)) >>> (define new-cache (make-vector n+1 0)) >>> (vector-copy! new-cache 0 cache) >>> (set! cache-size n+1) >>> (set! cache new-cache)])) >>> >>> (: loop1 : Integer Integer Integer -> Integer) >>> (define (loop1 k m s) >>> (cond [(< m 0) s] >>> [else (loop1 (+ k 1) >>> (- m (+ (* 3 k) 1)) >>> (if (odd? k) (+ s (p m)) (- s (p m))))])) >>> >>> (: loop2 : Integer Integer Integer -> Integer) >>> (define (loop2 k m s) >>> (cond [(< m 0) s] >>> [else (loop2 (- k 1) >>> (+ m (* 3 k) -2) >>> (if (odd? k) (+ s (p m)) (- s (p m))))])) >>> >>> (: p : Integer -> Integer) >>> (define (p n) >>> (define cached (vector-ref cache n)) >>> (cond [(exact-zero? cached) >>> (define pn (+ (loop1 1 (- n 1) 0) >>> (loop2 -1 (- n 2) 0))) >>> (vector-set! cache n pn) >>> pn] >>> [else cached])) >>> >>> (: partitions : Integer -> Integer) >>> (define (partitions n) >>> (cond [(< n 0) 0] >>> [else (grow-cache n) >>> (p n)])) >>> >>> >>> >>> >>> >>> 2014-06-28 16:26 GMT+02:00 Neil Toronto <neil.toro...@gmail.com>: >>> > Possible culprit: growing the vector by 1 instead of by powers of 2. >>> > >>> > Also, vector-ref! may not be especially fast. In >>> particular, it always applies a higher-order function, but >>> hash-ref! only does that when an entry is missing. >>> > >>> > Neil >>> > >>> > Sent from my iPhone >>> > >>> >> On Jun 28, 2014, at 7:04 AM, "Jos Koot" <jos.k...@gmail.com> wrote: >>> >> >>> >> Thanks for the conversion. I hope the code can be useful. >>> >> >>> >> Strange timing differences. I would expect a vector to be >>> faster, but I am no expert on the inside of Racket. Looking >>> at profiles with (partitions 10000) I see no special parts >>> taking relatively exorbitant much more time in one version >>> than in the other one. >>> >> >>> >> Sorry I can't help you on this. Maybe experts of the team >>> can shed light? >>> >> >>> >> Best wishes, Jos >>> >> >>> >> >>> >> >>> >>> -----Original Message----- >>> >>> From: jensaxelsoega...@gmail.com >>> >>> [mailto:jensaxelsoega...@gmail.com] On Behalf Of Jens Axel Søgaard >>> >>> Sent: sábado, 28 de junio de 2014 12:07 >>> >>> To: Jos Koot >>> >>> Cc: Neil Toronto; Racket Users List >>> >>> Subject: Re: [racket] FW: q about code for partitions >>> >>> >>> >>> Hi, >>> >>> >>> >>> I have converted your code to Typed Racket and made two versions. >>> >>> The first version use a hash as cache and the second version >>> >>> us a vector. >>> >>> >>> >>> Timings show that the vector version is 1.5 to 2 times >>> slower than the >>> >>> hash version. >>> >>> >>> >>> I don't understand this. Is there anything that can be done >>> >>> to improve it? >>> >>> >>> >>> The two versions can be seen here in color: >>> >>> >>> >>> http://pasterack.org/pastes/12166 >>> >>> http://pasterack.org/pastes/16085 >>> >>> >>> >>> They are also attached. >>> >>> >>> >>> I used (time (begin (partitions 50000) 0)) as benchmark. >>> >>> >>> >>> >>> >>> >>> >>> >>> >>> 2014-06-28 9:54 GMT+02:00 Jos Koot <jos.k...@gmail.com>: >>> >>>> Sorry, forgot to post the following to the users list. >>> >>>> >>> >>>> Hi, >>> >>>> count partitions, much faster and exact. >>> >>>> You may want to put the hash or part of it within function >>> >>> p such as to >>> >>>> avoid spllling much memory. >>> >>>> Jos >>> >>>> >>> >>>> #lang racket >>> >>>> >>> >>>> (require math/number-theory) >>> >>>> >>> >>>> (define p-hash (make-hash '((0 . 1)))) >>> >>>> >>> >>>> (define (p n) >>> >>>> (hash-ref! p-hash n >>> >>>> (λ () >>> >>>> (+ >>> >>>> (let loop ((k 1) (m (sub1 n)) (s 0)) >>> >>>> (if (< m 0) s >>> >>>> (loop (add1 k) (- m (add1 (* 3 k))) (if (odd? k) (+ s >>> >>> (p m)) (- s (p >>> >>>> m)))))) >>> >>>> (let loop ((k -1) (m (- n 2)) (s 0)) >>> >>>> (if (< m 0) s >>> >>>> (loop (sub1 k) (+ m (* 3 k) -2) (if (odd? k) (+ s (p >>> >>> m)) (- s (p >>> >>>> m)))))))))) >>> >>>> >>> >>>> (time (for ((n (in-range 0 1000))) (p n))) >>> >>>> (time (for ((n (in-range 0 1000))) (partitions n))) >>> >>>> (void (time (p 10000))) >>> >>>> >>> >>>> (for/and ((n (in-range 0 1000))) (= (partitions n) (p n))) >>> >>>> >>> >>>> (read-line) >>> >>>> >>> >>>> ; results with racket: >>> >>>> ; cpu time: 16 real time: 16 gc time: 0 >>> >>>> ; cpu time: 8845 real time: 8845 gc time: 111 >>> >>>> ; cpu time: 577 real time: 578 gc time: 0 >>> >>>> ; #t >>> >>>> >>> >>>> >>> >>>> >>> >>>> ____________________ >>> >>>> Racket Users list: >>> >>>> http://lists.racket-lang.org/users >>> >>> >>> >>> >>> >>> >>> >>> -- >>> >>> -- >>> >>> Jens Axel Søgaard >>> >> >>> >>> >>> >>> -- >>> -- >>> Jens Axel Søgaard >> >> >> ____________________ >> Racket Users list: >> http://lists.racket-lang.org/users -- -- Jens Axel Søgaard ____________________ Racket Users list: http://lists.racket-lang.org/users