unofficial mirror of guile-devel@gnu.org 
 help / color / mirror / Atom feed
* Fun with guile, Erastones + goldbach conjecture
@ 2013-04-08 22:03 Stefan Israelsson Tampe
  2013-04-09 10:24 ` Stefan Israelsson Tampe
  2013-04-10  0:11 ` Ian Price
  0 siblings, 2 replies; 5+ messages in thread
From: Stefan Israelsson Tampe @ 2013-04-08 22:03 UTC (permalink / raw)
  To: guile-devel, guile-user

[-- Attachment #1: Type: text/plain, Size: 1806 bytes --]

Hi all,

The program below is an interesting variant of a sieve that given an
even number seams to constructs two primes that added together becomes 
the even 
number, the file below does this construction for n = 3 ... 1000.

Have fun!

/Stefan


(use-modules (srfi srfi-1))

(define (analyze k)
  (define n (* k 2))
  (define l (apply circular-list (map (lambda (X) #f) (iota n))))
  (define (shift l k)
    (let loop ((l l) (k k))
      (if (= k 0) 
	  l
	  (loop (cdr l) (- k 1)))))

  (define (next loop)
    (let lp ((ll l) (i 0))
      (if (= i n)
	  l
	  (if (car ll)
	      (lp (cdr ll) (+ i 1))
	      (loop i l 0)))))
	  
  (define (M)
    (let lp ((l l) (k n) (M -1))
      (if (= k 0)
	  M
	  (let ((c (caar l)))
	    (if (< M c)
		(lp (cdr l) (- k 1) c)
		(lp (cdr l) (- k 1) M))))))

  (define (place x)
    (let loop ((ll l) (i 0))
      (if (equal? (car ll) x)
	  i
	  (loop (cdr ll) (+ i 1)))))
      
  (set-car! (cdr l) (cons 1 0))
  (set-car! (shift l (- n 1)) (cons 1 0))
  (let loop ((m 2) (ll l) (k 0))
    (let ((ll (shift ll m)))
      (if (and (pair? (car ll)) (eq? (caar ll) m))
	  (next loop)
	  (begin
	    (unless (car ll) (set-car! ll (cons m k)) (set! k (+ k 1)))
	    (loop m ll k)))))

  (let* ((M   (M))
	 (ll  (let lp ((ll l) (k n))
		(if (= k 0)
		    '()
		    (cons (car ll) (lp (cdr ll) (- k 1))))))
	 (ll  (fold (lambda (k r)(if (eq? (car k) M) (cons k r) r)) '() ll))
	 (ll  (sort ll (lambda (x y) (< (cdr x) (cdr y))))))

    (cond 
     ((= (length ll) 1)
      (* (place (car ll)) 2))
     (else
      (+ (place (car ll)) (place (car (last-pair ll))))))))
   
(let lp ((i 3))
  (if (= i 1000)
      (pk 'ok)
      (begin
	(if (not (= (* 2 i) (analyze i)))
	    (format #t "~a != (analyze ~a) == ~a~%" (* 2 i) (* 2 i) 
		    (analyze (* 2i))))
	(lp (+ i 1)))))

[-- Attachment #2: goldbach.scm --]
[-- Type: text/x-scheme, Size: 1560 bytes --]

(use-modules (srfi srfi-1))

(define (analyze k)
  (define n (* k 2))
  (define l (apply circular-list (map (lambda (X) #f) (iota n))))
  (define (shift l k)
    (let loop ((l l) (k k))
      (if (= k 0) 
	  l
	  (loop (cdr l) (- k 1)))))

  (define (next loop)
    (let lp ((ll l) (i 0))
      (if (= i n)
	  l
	  (if (car ll)
	      (lp (cdr ll) (+ i 1))
	      (loop i l 0)))))
	  
  (define (M)
    (let lp ((l l) (k n) (M -1))
      (if (= k 0)
	  M
	  (let ((c (caar l)))
	    (if (< M c)
		(lp (cdr l) (- k 1) c)
		(lp (cdr l) (- k 1) M))))))

  (define (place x)
    (let loop ((ll l) (i 0))
      (if (equal? (car ll) x)
	  i
	  (loop (cdr ll) (+ i 1)))))
      
  (set-car! (cdr l) (cons 1 0))
  (set-car! (shift l (- n 1)) (cons 1 0))
  (let loop ((m 2) (ll l) (k 0))
    (let ((ll (shift ll m)))
      (if (and (pair? (car ll)) (eq? (caar ll) m))
	  (next loop)
	  (begin
	    (unless (car ll) (set-car! ll (cons m k)) (set! k (+ k 1)))
	    (loop m ll k)))))

  (let* ((M   (M))
	 (ll  (let lp ((ll l) (k n))
		(if (= k 0)
		    '()
		    (cons (car ll) (lp (cdr ll) (- k 1))))))
	 (ll  (fold (lambda (k r)(if (eq? (car k) M) (cons k r) r)) '() ll))
	 (ll  (sort ll (lambda (x y) (< (cdr x) (cdr y))))))

    (cond 
     ((= (length ll) 1)
      (* (place (car ll)) 2))
     (else
      (+ (place (car ll)) (place (car (last-pair ll))))))))
   
(let lp ((i 3))
  (if (= i 1000)
      (pk 'ok)
      (begin
	(if (not (= (* 2 i) (analyze i)))
	    (format #t "~a != (analyze ~a) == ~a~%" (* 2 i) (* 2 i) 
		    (analyze (* 2i))))
	(lp (+ i 1)))))
  

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: Fun with guile, Erastones + goldbach conjecture
  2013-04-08 22:03 Fun with guile, Erastones + goldbach conjecture Stefan Israelsson Tampe
@ 2013-04-09 10:24 ` Stefan Israelsson Tampe
  2013-04-09 19:35   ` Panicz Maciej Godek
  2013-04-10  0:11 ` Ian Price
  1 sibling, 1 reply; 5+ messages in thread
From: Stefan Israelsson Tampe @ 2013-04-09 10:24 UTC (permalink / raw)
  To: guile-devel, guile-user

Actually, inserting a primality check 500 out of 1000 items is nonprime.
but this algorithm still shows some interesting aspect and adding to the
algorithm to sellect the inner pair that sum to n, we do get primality for all
n = 3 ... 1000. Kind of cool.

-------------------------------------------------------
(use-modules (srfi srfi-1))
(use-modules (ice-9 pretty-print))
(define pp pretty-print)


(define (prim x)
  (let lp ((i 2))
    (if (<= i (/ x 2))
(if (= (modulo x i) 0)
   #f
   (lp (+ i 1)))
#t)))

(define prims (let loop ((i 2))
(if (< i 10000)
   (if (prim i)
(cons i (loop (+ i 1)))
(loop (+ i 1)))
   '())))

(define (factor x)
  (let lp ((ps prims))
    (if (< (car ps) (/ x 2))
(if (= (modulo x (car ps)) 0)
   (cons (car ps) (lp (cdr ps)))
   (lp (cdr ps)))
'())))

(define L3 '())

(define (analyze k)
  (define n (* k 2))
  (define l (apply circular-list (map (lambda (X) #f) (iota n))))
  (define (shift l k)
    (let loop ((l l) (k k))
      (if (= k 0)
          l
          (loop (cdr l) (- k 1)))))

  (define (next loop)
    (let lp ((ll l) (i 0))
      (if (= i n)
          l
          (if (car ll)
              (lp (cdr ll) (+ i 1))
              (loop i l 0)))))

  (define (M)
    (let lp ((l l) (k n) (M -1))
      (if (= k 1)
          M
          (let ((c (caar l)))
            (if (< M c)
                (lp (cdr l) (- k 1) c)
                (lp (cdr l) (- k 1) M))))))

  (define (place x)
    (let loop ((ll l) (i 0))
      (if (equal? (car ll) x)
          i
          (loop (cdr ll) (+ i 1)))))

  (define (splitx x M)
    (let lp1 ((xx x) (l '()) (r '()) (i 0))
      (if (pair? xx)
 (if (= (caar xx) M)
     (if (= (cadar xx) i)
 (lp1 (cdr xx) (cons (car xx) l) r (+ i 1))
 (lp1 (cdr xx) l r i))
     (lp1 (cdr xx) l r i))
 (if (null? l)
     (reverse r)
     (lp1 x '() (cons (reverse l) r) i)))))

  (define (inner l)
    (let ((n (length l)))
      (if (= (modulo n 2) 1)
 (list-ref l (/ (- n 1) 2))
 (append (list-ref l (- (/ n 2) 1))
 (list-ref l (- (/ n 2) 0))))))

  (define (shrink l)
    (let lp ((l (apply append l)) (i 0))
      (let ((a (list-ref (car l) 2)))
(if (and (null? (factor (- n a))) (null? (factor a)))
   a
   (if (< i (length l))
(lp (cdr l) (+ i 1))
(error "could not find conjecture I"))))))

  (define (thin l)
    (let lp ((l l) (r (reverse l)) (p -1))
      (if (pair? r)
 (let ((x (car r)))
   (let lp2 ((ll l))
     (if (pair? ll)
 (if (= (+ (list-ref (car ll) 2)
   (list-ref x 2))
n)
     (lp l (cdr r) (list-ref (car ll) 2))
     (lp2 (cdr ll)))
 p)))
 p)))

  (set-car! (cdr l)           (cons 1 0))
  (set-car! (shift l (- n 1)) (cons 1 1))

  (let loop ((m 2) (ll l) (k 1))
    (let ((ll (shift ll m)))
      (if (and (pair? (car ll))
      (eq? (caar ll) m))
          (next loop)
          (begin
            (unless (car ll) (set-car! ll (cons m k)) (set! k (+ k 1)))
            (loop m ll k)))))

  (let* ((M   (M))
         (l2  (let lp ((ll l) (k 0))
                (if (= k n)
                    '()
                    (cons (list (caar ll) (cdar ll) k)
 (lp (cdr ll) (+ k 1))))))
(l3  (splitx l2 M))
(ll  (inner l3))
         (ll  (fold (lambda (k r)(if (eq? (car k) M) (cons k r) r)) '() ll))
         (ll  (sort ll (lambda (x y) (< (cadr x) (cadr y))))))

    (set! l l2)
    (set! L3 l3)
    (thin ll)#;(place (car ll))))


(let lp ((i 3) (fail 0))
  (if (= i 1000)
      (pk `(,i ,fail))
      (let ((p (analyze i)))
(pk `(,i : ,p ,(- (* 2 i) p)))
(if (null? (factor (- (* 2 i) p)))
   (lp (+ i 1) fail)
   (begin
     (pp `(fail ,L3))
     (lp (+ i 1) (+ fail 1)))))))




On Tue, Apr 9, 2013 at 12:03 AM, Stefan Israelsson Tampe
<stefan.itampe@gmail.com> wrote:
> Hi all,
>
> The program below is an interesting variant of a sieve that given an
> even number seams to constructs two primes that added together becomes
> the even
> number, the file below does this construction for n = 3 ... 1000.
>
> Have fun!
>
> /Stefan
>
>
> (use-modules (srfi srfi-1))
>
> (define (analyze k)
>   (define n (* k 2))
>   (define l (apply circular-list (map (lambda (X) #f) (iota n))))
>   (define (shift l k)
>     (let loop ((l l) (k k))
>       (if (= k 0)
>           l
>           (loop (cdr l) (- k 1)))))
>
>   (define (next loop)
>     (let lp ((ll l) (i 0))
>       (if (= i n)
>           l
>           (if (car ll)
>               (lp (cdr ll) (+ i 1))
>               (loop i l 0)))))
>
>   (define (M)
>     (let lp ((l l) (k n) (M -1))
>       (if (= k 0)
>           M
>           (let ((c (caar l)))
>             (if (< M c)
>                 (lp (cdr l) (- k 1) c)
>                 (lp (cdr l) (- k 1) M))))))
>
>   (define (place x)
>     (let loop ((ll l) (i 0))
>       (if (equal? (car ll) x)
>           i
>           (loop (cdr ll) (+ i 1)))))
>
>   (set-car! (cdr l) (cons 1 0))
>   (set-car! (shift l (- n 1)) (cons 1 0))
>   (let loop ((m 2) (ll l) (k 0))
>     (let ((ll (shift ll m)))
>       (if (and (pair? (car ll)) (eq? (caar ll) m))
>           (next loop)
>           (begin
>             (unless (car ll) (set-car! ll (cons m k)) (set! k (+ k 1)))
>             (loop m ll k)))))
>
>   (let* ((M   (M))
>          (ll  (let lp ((ll l) (k n))
>                 (if (= k 0)
>                     '()
>                     (cons (car ll) (lp (cdr ll) (- k 1))))))
>          (ll  (fold (lambda (k r)(if (eq? (car k) M) (cons k r) r)) '() ll))
>          (ll  (sort ll (lambda (x y) (< (cdr x) (cdr y))))))
>
>     (cond
>      ((= (length ll) 1)
>       (* (place (car ll)) 2))
>      (else
>       (+ (place (car ll)) (place (car (last-pair ll))))))))
>
> (let lp ((i 3))
>   (if (= i 1000)
>       (pk 'ok)
>       (begin
>         (if (not (= (* 2 i) (analyze i)))
>             (format #t "~a != (analyze ~a) == ~a~%" (* 2 i) (* 2 i)
>                     (analyze (* 2i))))
>         (lp (+ i 1)))))



^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: Fun with guile, Erastones + goldbach conjecture
  2013-04-09 10:24 ` Stefan Israelsson Tampe
@ 2013-04-09 19:35   ` Panicz Maciej Godek
  2013-04-10  0:18     ` Ian Price
  0 siblings, 1 reply; 5+ messages in thread
From: Panicz Maciej Godek @ 2013-04-09 19:35 UTC (permalink / raw)
  To: Stefan Israelsson Tampe; +Cc: guile-user@gnu.org, guile-devel

[-- Attachment #1: Type: text/plain, Size: 738 bytes --]

Hey,
I see that the style of your code is fairly unorthodox.
I'd suggest you to read the following chapters of SICP,
if you haven't already:
Section 3.5 (Streams), which introduces the notion
of streams, or lazy lists (that can be infinite), with the
most amazing example of Erastostenes' sieve
implementation, as well as sections 4.1 and 4.3 of
Chapter 4 (Metalinguistic abstraction). The first one
presents the notion of "meta-circular evaluator", which
is then used to implement "non-deterministic evaluator",
which allows to express certain problems extremely
elegantly. Simultaneously, the book shows many
examples of the finest programming style in Scheme.
I think you might find it quite entertaining and useful.

Best regards,
M.

[-- Attachment #2: Type: text/html, Size: 1446 bytes --]

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: Fun with guile, Erastones + goldbach conjecture
  2013-04-08 22:03 Fun with guile, Erastones + goldbach conjecture Stefan Israelsson Tampe
  2013-04-09 10:24 ` Stefan Israelsson Tampe
@ 2013-04-10  0:11 ` Ian Price
  1 sibling, 0 replies; 5+ messages in thread
From: Ian Price @ 2013-04-10  0:11 UTC (permalink / raw)
  To: Stefan Israelsson Tampe; +Cc: guile-user, guile-devel

Stefan Israelsson Tampe <stefan.itampe@gmail.com> writes:

> Hi all,
>
> The program below is an interesting variant of a sieve that given an
> even number seams to constructs two primes that added together becomes 
> the even 
> number, the file below does this construction for n = 3 ... 1000.

Amusing, but I feel that code like that needs a big massive disclaimer
at the top saying "CAUTION: DO NOT ACTUALLY WRITE SCHEME LIKE THIS".

Mutable circular lists? No thank you :)
Actually, I think you understand this yourself, since the circularity
infected all the procedures, and made them a little more complex than
they'd usually be.

For the newer Schemers, I've added a bunch of annotations.

> (use-modules (srfi srfi-1))
>
> (define (analyze k)
>   (define n (* k 2))
>   (define l (apply circular-list (map (lambda (X) #f) (iota n))))
Personally, I would move l down closer to where it is being mutated,
rather than having a bunch of procedures in the way.

>   (define (shift l k)
>     (let loop ((l l) (k k))
>       (if (= k 0) 
> 	  l
> 	  (loop (cdr l) (- k 1)))))
    (define shift drop)

>   (define (next loop)
>     (let lp ((ll l) (i 0))
>       (if (= i n)
> 	  l
> 	  (if (car ll)
> 	      (lp (cdr ll) (+ i 1))
> 	      (loop i l 0)))))
The continuation passing here is a bit weird, I would do two mutually
recursive procedures instead.

The additional state makes it harder to break into separate procedures,
but it feels to me like you should be able change this into a
drop-while.
> 	  
>   (define (M)
>     (let lp ((l l) (k n) (M -1))
>       (if (= k 0)
> 	  M
> 	  (let ((c (caar l)))
> 	    (if (< M c)
> 		(lp (cdr l) (- k 1) c)
> 		(lp (cdr l) (- k 1) M))))))
M was a terrible name. :)
I'd either suggest moving the if into the third clause of loop, or
rewriting this as

    (define (M)
      ;; maybe factor into procedure 'maximum-by'
      (fold-right (lambda (x prev) (max (car x) prev))
                  -1
                  (take l n)))

Yeah it allocates, but it was either that or write a foldr for
cyclic lists.

>   (define (place x)
>     (let loop ((ll l) (i 0))
>       (if (equal? (car ll) x)
> 	  i
> 	  (loop (cdr ll) (+ i 1)))))
    (define (place x)
      (list-index (lambda (y) (eqv? x y)) l))

>   (set-car! (cdr l) (cons 1 0))
>   (set-car! (shift l (- n 1)) (cons 1 0))
>   (let loop ((m 2) (ll l) (k 0))
>     (let ((ll (shift ll m)))
>       (if (and (pair? (car ll)) (eq? (caar ll) m))
> 	  (next loop)
> 	  (begin
> 	    (unless (car ll) (set-car! ll (cons m k)) (set! k (+ k 1)))
> 	    (loop m ll k)))))
Not quite sure what to make of this.

>   (let* ((M   (M))
> 	 (ll  (let lp ((ll l) (k n))
> 		(if (= k 0)
> 		    '()
> 		    (cons (car ll) (lp (cdr ll) (- k 1))))))
         (ll  (take l n))
> 	 (ll  (fold (lambda (k r)(if (eq? (car k) M) (cons k r) r)) '() ll))
         (ll  (filter (lambda (x) (eq? (car x) M)) ll))

Granted, that doesn't have the same ordering, but you are sorting the
result anyway.

> 	 (ll  (sort ll (lambda (x y) (< (cdr x) (cdr y))))))
>
>     (cond 
>      ((= (length ll) 1)
>       (* (place (car ll)) 2))
>      (else
>       (+ (place (car ll)) (place (car (last-pair ll))))))))
        (+ (place (car l1)) (place (last l1)))

For the purposes of your demonstration, it doesn't really matter, but it
would be a better idea to return those two values, rather than the sum.
Otherwise, analyze just becomes a very long-winded doubling function :)

> (let lp ((i 3))
>   (if (= i 1000)
>       (pk 'ok)
>       (begin
> 	(if (not (= (* 2 i) (analyze i)))
> 	    (format #t "~a != (analyze ~a) == ~a~%" (* 2 i) (* 2 i) 
> 		    (analyze (* 2i))))
btw, Typo here               ^^^^^^
> 	(lp (+ i 1)))))
>   

Maybe I'll meditate on this more, and post a "schemier" version.

-- 
Ian Price -- shift-reset.com

"Programming is like pinball. The reward for doing it well is
the opportunity to do it again" - from "The Wizardy Compiled"



^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: Fun with guile, Erastones + goldbach conjecture
  2013-04-09 19:35   ` Panicz Maciej Godek
@ 2013-04-10  0:18     ` Ian Price
  0 siblings, 0 replies; 5+ messages in thread
From: Ian Price @ 2013-04-10  0:18 UTC (permalink / raw)
  To: Panicz Maciej Godek; +Cc: guile-user@gnu.org, guile-devel

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset=iso-2022-jp-2, Size: 2229 bytes --]

Panicz Maciej Godek <godek.maciek@gmail.com> writes:

> Section 3.5 (Streams), which introduces the notion
> of streams, or lazy lists (that can be infinite), with the
> most amazing example of Erastostenes' sieve^[,A ^[(B
> implementation, as well as sections^[,A ^[(B4.1^[,A ^[(Band^[,A ^[(B4.3^[,A ^[(Bof

My pedant sense is tingling :P

Two concerns here.

First, lazy lists as presented in SICP are subject to off-by-1 coding
problems. You see it throughout the streams chapter, and in the
non-deterministic evaluator chapter by occasional smatterings of 'force'
and 'delay' about the place.  In the next release of Guile, we will have
an implementation of SRFI 41[0], which does not have these problems.

Secondly, that is not actually the sieve of Eratosthenes, but Trial
Division.  Melissa E. O'Neill has a lovely paper about this[1], giving
performances analyses of both.

And before you object to me calling SICP's sieve ^[$B!H^[(Bfake^[$B!I^[(B...
^[$B!H^[(BSome readers may feel that despite all of these concerns, the earlier
algorithm is somehow ^[$B!H^[(Bmorally^[$B!I^[(B the Sieve of Eratosthenes. I would
argue, however, that they are confusing a mathematical abstraction drawn
from the Sieve of Eratosthenes with the actual algorithm. The
algorithmic details, such as how you remove all the multiples of 17,
matter.^[$B!I^[(B

I have an implementation of the genuine sieve available[2], that you
will be able to run when the next release comes out. (Needs pfds).

Okay, pedant sense sufficiently exercised for now.

SICP is a fine book IMO, but it isn't perfect. Section 3 is not
fantastic, for a variety of reasons, and I feel people are better served
learning recursion on recursive data structures (like lists or trees),
rather than the way SICP does with numbers (yes, the naturals are
recursive, but many of the algorithms, like fast-exponentiation, rely on
recursion other than on the predecessor).

0. http://srfi.schemers.org/srfi-41/srfi-41.html
1. http://www.cs.hmc.edu/~oneill/papers/Sieve-JFP.pdf
2. https://github.com/ijp/ijputils/blob/master/streams.sls#L73
-- 
Ian Price -- shift-reset.com

"Programming is like pinball. The reward for doing it well is
the opportunity to do it again" - from "The Wizardy Compiled"



^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2013-04-10  0:18 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-04-08 22:03 Fun with guile, Erastones + goldbach conjecture Stefan Israelsson Tampe
2013-04-09 10:24 ` Stefan Israelsson Tampe
2013-04-09 19:35   ` Panicz Maciej Godek
2013-04-10  0:18     ` Ian Price
2013-04-10  0:11 ` Ian Price

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).