#!/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)))))))