unofficial mirror of guile-user@gnu.org 
 help / color / mirror / Atom feed
* I wrote a 3+1 guile program, feedback welcome
@ 2018-11-07 15:14 Joshua Branson
  2018-11-08  9:37 ` Jérémy Korwin-Zmijowski
  0 siblings, 1 reply; 2+ messages in thread
From: Joshua Branson @ 2018-11-07 15:14 UTC (permalink / raw
  To: guile-user

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


Hello,

I spent a week or two working on the 3+1 problem.  The 3+1 problem is a
fun number theory conjecture.  It states that there exists a procedure
for turning all positive whole integers into 1.  The procedure is:

If the number is even, then divide it by two.
If the number is odd, multiply by 3 and add 1.
repeat.

I decided to write a program to graph the number of iterations it takes
for the set of numbers 2-n to reach 1.  It uses ice-9 getopt-long, so
the usual --help and --version work.  It uses gnuplot, because I
couldn't get guile-charting to work.  If anyone has enough free time to
comment on the state of this program, or any tips about how to make it
better, etc. that would be most helpful.

Thanks,


Joshua


[-- Attachment #2: collatz.scm --]
[-- Type: text/plain, Size: 7807 bytes --]

#!/usr/bin/guile \
-e main -s
!#

;; This is a program that checks to see if a string of numbers has
;; repeatitive numbers...
;;  take any number, if even / 2,  if odd * 3 + 1  repeat.
;; The goal is to plot the number of steps it takes to produce 1 from 1-100
;; gnuplot can plot things via a command line from standard in via
;; gnuplot -

;; To give gnuplot commands directly in the command line, using the "-persist" option so that the plot remains on the screen afterwards:
;; gnuplot -persist -e "set title 'Sine curve'; plot sin(x)"
;; To set user-defined variables a and s prior to executing commands from a file:
;; gnuplot -e "a=2; s='file.png'" input.gpl

;; use these modules to help my process the command line arguments.
(use-modules (ice-9 getopt-long))
;;(use-modules (charting))
(use-modules (oop goops))
;; (use-modules (fibers))
(use-modules (ice-9 textual-ports)) ;;open-output-file

;; take a number
;; if even / 2
;; if odd * 3 + 1
;; repeat
;; You should end at 1

;;(define counter 0)
;; Every time you call counter, it returns the next higher positive integer
;; (counter #:key #t) resets the value to 0
(define counter
  (let ((counter 0))
    (lambda* (#:key reset)
      (if reset
          (set! counter 0)
          (begin
            (set! counter (+ counter 1))
            counter)))))

;; playing with fibers
;; (run-fibers
;;  (spawn-fiber
;;   (lambda ()
;;     (display
;;      (let loop (n 10)
;;        (if (> n 0)
;;            (cons n (cons loop (- n 1)))
;;            '())))
;;     )
;;   (spawn-fiber
;;    (lambda ()
;;      (display
;;       (let loop (n 20)
;;         (if (> n 10)
;;             (cons n (cons loop (- n 1)))
;;             '())))))))


;; implement the collatz (3 + 1) algorithm on a number.
;; Return the number of steps it takes to turn the number into 1
(define (collatz n)
  (when (>= n 1) ;; n must be greater than or equal to 1
    (let ((count (counter)))
      (cond
       ((= n 1)
        (counter #:reset #t)
        (- count 1))
       ((even? n)
        ;; (display (string-append "collatz (/ " (number->string n) " 2)\n"))
        (collatz (/ n 2)))
       ((odd? n)
        ;; (display (string-append  "collatz (- (* " (number->string n) " 3) 1)\n"))
        (collatz (+ (* n 3) 1)))))))

;; return the number with the most iterations required to get to 1
;; within the set 0-n.  return value is '(number number)
(define (collatz-set n)
  ;; most iterative number the number that takes the most iterations
  ;; to get to 1. (cdr most-it-number) is the number
  ;; (car (cdr most-it-number)) is the number of iterations
  (let ([most-it-number '(0 0)]
        [iterations 0])
    (let loop ((number n)) ;; loop through the numbers 0-n
      (when (> number 1)
        (set! iterations (collatz number))
        ;; error checking (display number) (display " has ")
        ;; error checking (display iterations) (display " iterations\n")
        ;; if the current number's iterations was more than the last one
        ;; then set most-it-number to the new number
        (when (> iterations
                 (car (cdr most-it-number)))
          (set! most-it-number (list number iterations)))
        (loop (- number 1))))
    most-it-number))

;; this function will create a gnuplot script to draw a line through a scatter plot
(define (create-plot-script data-file)
  ;; use a let here instead of all the defines
  (letrec ([script-filename "/tmp/plot.dem"]
           [output-script-port (open-output-file script-filename)])

    (put-string output-script-port "set style fill  transparent solid 1 noborder\n")
    (put-string output-script-port "set style circle radius 0.5\n")
    (put-string output-script-port
                (string-append "plot '" data-file "' with circles"))
    (force-output output-script-port)
    (close-port output-script-port)
    script-filename))



;; graphs a scatter plot from the set of numbers 2-n
;; what's wrong here?  and wow functional programming recursively sure makes for consice code!
(define (graph-collatz-set n)
  ;; number-iterations is the list of numbers and their iterations
  ;; ie:  '((2 . 1) (3 . 8) (4 . 2) ...)
  (letrec ([data-filename "/tmp/data.dat"]
           [output-data-port (open-output-file data-filename)]
           [script-filename (create-plot-script data-filename)])
    (let loop ((number 2) (iterations (collatz 2))) ;; loop through the numbers 0-n
      (when (>= n number)
        ;; write to a file
        (put-string output-data-port
                    (string-append (number->string number) "\t" (number->string iterations) "\n"))
        ;;(display (string-append "number is " number " iterations is " iterations "\n"))
        (loop (+ number 1) (collatz (+ number 1)))))
    (force-output output-data-port)
    (close-port output-data-port)
    (system (string-append "gnuplot "  "-p " script-filename)))
  ;;(delete-file data-filename)
  ;;(delete-file script-filename)
  ;; if guile-charting worked
  ;; (make-scatter-plot
  ;;  "3+1 conjecture"
  ;;  (list
  ;;   (append '("numbers")
  ;;           (let loop ((number 2) (iterations (collatz 2))) ;; loop through the numbers 0-n
  ;;             (if (>= n number)
  ;;                 (cons (cons number iterations) (loop (+ number 1) (collatz (+ number 1))))
  ;;                 '())))))
  )


(define (main args)
  ;;the option specification tells getopt-long how
  ;; to parse the command line
  (let* ((option-spec '((version (single-char #\v) (value #f))
                        (help    (single-char #\h) (value #f))
                        (graph   (single-char #\g) (value #t))
                        (number  (single-char #\n) (value #t))
                        ;; a set of numbers
                        (set     (single-char #\s) (value #t))
                        ))
         ;; tell getopt-long to parse the command line and put the
         ;; data in options
         (options (getopt-long args option-spec))
         ;; was  --help or -h used?
         (help-wanted    (option-ref options 'help #f))
         (version-wanted (option-ref options 'version #f))
         ;; fixme.  This How do I know if graph was wanted?
         (graph-wanted   (option-ref options 'graph #f))
         (number-wanted  (option-ref options 'number #f))
         (set-wanted     (option-ref options 'set #f)))
    (if (or number-wanted version-wanted help-wanted set-wanted graph-wanted)
        (cond
         (version-wanted
          (display "collatz version 0.1\n"))
         (help-wanted
          (display "collatz [options]\n")
          (display "")
          (display "-v  --version  Display version\n")
          (display "-h, --help     Display this help info\n")
          (display "-g, --graph    Graph the set of numbers' iterations via gnuplot\n")
          (display "               ie: collatz -g 500\n")
          (display "-n, --number   Returns the number of iterations required to turn this number to 1\n")
          (display "-s, --set      Specify a set of numbers, to which to apply the 3 + 1 formula.\n")
          (display "               ie: collatz -s 500 will return the number which requires the most\n")
          (display "               iterations in the set of numbers 2-500\n")
          )
         (number-wanted
          (display (collatz (string->number number-wanted)))
          (display "\n"))
         (set-wanted
          (let ((result (collatz-set (string->number set-wanted))))
            (display "In the set of 2-")
            (display set-wanted)
            (display " ")
            (display (car result))
            (display " has the most iterations with ")
            (display (car (cdr result)))
            (display " iterations\n")))
         (graph-wanted
          (graph-collatz-set (string->number graph-wanted)))))))

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

* Re: I wrote a 3+1 guile program, feedback welcome
  2018-11-07 15:14 I wrote a 3+1 guile program, feedback welcome Joshua Branson
@ 2018-11-08  9:37 ` Jérémy Korwin-Zmijowski
  0 siblings, 0 replies; 2+ messages in thread
From: Jérémy Korwin-Zmijowski @ 2018-11-08  9:37 UTC (permalink / raw
  To: guile-user, Joshua Branson

Hey ! Sounds great I will look at it !

Cheers

Le 7 novembre 2018 16:14:06 GMT+01:00, Joshua Branson <jbranso@fastmail.com> a écrit :
>
>Hello,
>
>I spent a week or two working on the 3+1 problem.  The 3+1 problem is a
>fun number theory conjecture.  It states that there exists a procedure
>for turning all positive whole integers into 1.  The procedure is:
>
>If the number is even, then divide it by two.
>If the number is odd, multiply by 3 and add 1.
>repeat.
>
>I decided to write a program to graph the number of iterations it takes
>for the set of numbers 2-n to reach 1.  It uses ice-9 getopt-long, so
>the usual --help and --version work.  It uses gnuplot, because I
>couldn't get guile-charting to work.  If anyone has enough free time to
>comment on the state of this program, or any tips about how to make it
>better, etc. that would be most helpful.
>
>Thanks,
>
>
>Joshua

Jérémy


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

end of thread, other threads:[~2018-11-08  9:37 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2018-11-07 15:14 I wrote a 3+1 guile program, feedback welcome Joshua Branson
2018-11-08  9:37 ` Jérémy Korwin-Zmijowski

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).