collatz.scm 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. #!/run/current-system/profile/bin/guile \
  2. -e main -s
  3. !#
  4. ;; This is a program that checks to see if a string of numbers has
  5. ;; repeatitive numbers...
  6. ;; take any number, if even / 2, if odd * 3 + 1 repeat.
  7. ;; The goal is to plot the number of steps it takes to produce 1 from 1-100
  8. ;; gnuplot can plot things via a command line from standard in via
  9. ;; gnuplot -
  10. ;; To give gnuplot commands directly in the command line, using the "-persist" option so that the plot remains on the screen afterwards:
  11. ;; gnuplot -persist -e "set title 'Sine curve'; plot sin(x)"
  12. ;; To set user-defined variables a and s prior to executing commands from a file:
  13. ;; gnuplot -e "a=2; s='file.png'" input.gpl
  14. ;; use these modules to help my process the command line arguments.
  15. (use-modules (ice-9 getopt-long)
  16. ;;(use-modules (charting))
  17. (oop goops)
  18. ;; (use-modules (fibers))
  19. (ice-9 textual-ports)) ;;open-output-file
  20. ;; take a number
  21. ;; if even / 2
  22. ;; if odd * 3 + 1
  23. ;; repeat
  24. ;; You should end at 1
  25. ;;(define counter 0)
  26. ;; Every time you call counter, it returns the next higher positive integer
  27. ;; (counter #:key #t) resets the value to 0
  28. (define counter
  29. (let ((counter 0))
  30. (lambda* (#:key reset)
  31. (if reset
  32. (set! counter 0)
  33. (begin
  34. (set! counter (+ counter 1))
  35. counter)))))
  36. ;; implement the collatz (3 + 1) algorithm on a number.
  37. ;; Return the number of steps it takes to turn the number into 1
  38. (define (collatz n)
  39. (when (>= n 1) ;; n must be greater than or equal to 1
  40. (let ((count (counter)))
  41. (cond
  42. ((= n 1)
  43. (counter #:reset #t)
  44. (- count 1))
  45. ((even? n)
  46. ;; (display (string-append "collatz (/ " (number->string n) " 2)\n"))
  47. (collatz (/ n 2)))
  48. ((odd? n)
  49. ;; (display (string-append "collatz (- (* " (number->string n) " 3) 1)\n"))
  50. (collatz (+ (* n 3) 1)))))))
  51. ;; return the number with the most iterations required to get to 1
  52. ;; within the set 0-n. return value is '(number number)
  53. (define (collatz-set n)
  54. ;; most iterative number the number that takes the most iterations
  55. ;; to get to 1. (cdr most-it-number) is the number
  56. ;; (car (cdr most-it-number)) is the number of iterations
  57. (let ([most-it-number '(0 0)]
  58. [iterations 0])
  59. (let loop ((number n)) ;; loop through the numbers 0-n
  60. (when (> number 1)
  61. (set! iterations (collatz number))
  62. ;; error checking (display number) (display " has ")
  63. ;; error checking (display iterations) (display " iterations\n")
  64. ;; if the current number's iterations was more than the last one
  65. ;; then set most-it-number to the new number
  66. (when (> iterations
  67. (car (cdr most-it-number)))
  68. (set! most-it-number (list number iterations)))
  69. (loop (- number 1))))
  70. most-it-number))
  71. ;; this function will create a gnuplot script to draw a line through a scatter plot
  72. (define (create-plot-script data-file)
  73. ;; use a let here instead of all the defines
  74. (letrec ([script-filename "/tmp/plot.dem"]
  75. [output-script-port (open-output-file script-filename)])
  76. (put-string output-script-port "set style fill transparent solid 1 noborder\n")
  77. (put-string output-script-port "set style circle radius 0.5\n")
  78. (put-string output-script-port
  79. (string-append "plot '" data-file "' with circles"))
  80. (force-output output-script-port)
  81. (close-port output-script-port)
  82. script-filename))
  83. ;; graphs a scatter plot from the set of numbers 2-n
  84. ;; what's wrong here? and wow functional programming recursively sure makes for consice code!
  85. (define (graph-collatz-set n)
  86. ;; number-iterations is the list of numbers and their iterations
  87. ;; ie: '((2 . 1) (3 . 8) (4 . 2) ...)
  88. (letrec ([data-filename "/tmp/data.dat"]
  89. [output-data-port (open-output-file data-filename)]
  90. [script-filename (create-plot-script data-filename)])
  91. (let loop ((number 2) (iterations (collatz 2))) ;; loop through the numbers 0-n
  92. (when (>= n number)
  93. ;; write to a file
  94. (put-string output-data-port
  95. (string-append (number->string number) "\t" (number->string iterations) "\n"))
  96. ;;(display (string-append "number is " number " iterations is " iterations "\n"))
  97. (loop (+ number 1) (collatz (+ number 1)))))
  98. (force-output output-data-port)
  99. (close-port output-data-port)
  100. (system (string-append "gnuplot " "-p " script-filename)))
  101. ;;(delete-file data-filename)
  102. ;;(delete-file script-filename)
  103. ;; if guile-charting worked
  104. ;; (make-scatter-plot
  105. ;; "3+1 conjecture"
  106. ;; (list
  107. ;; (append '("numbers")
  108. ;; (let loop ((number 2) (iterations (collatz 2))) ;; loop through the numbers 0-n
  109. ;; (if (>= n number)
  110. ;; (cons (cons number iterations) (loop (+ number 1) (collatz (+ number 1))))
  111. ;; '())))))
  112. )
  113. (define (main args)
  114. ;;the option specification tells getopt-long how
  115. ;; to parse the command line
  116. (let* ((option-spec '((version (single-char #\v) (value #f))
  117. (help (single-char #\h) (value #f))
  118. (graph (single-char #\g) (value #t))
  119. (number (single-char #\n) (value #t))
  120. ;; a set of numbers
  121. (set (single-char #\s) (value #t))
  122. ))
  123. ;; tell getopt-long to parse the command line and put the
  124. ;; data in options
  125. (options (getopt-long args option-spec))
  126. ;; was --help or -h used?
  127. (help-wanted (option-ref options 'help #f))
  128. (version-wanted (option-ref options 'version #f))
  129. ;; fixme. This How do I know if graph was wanted?
  130. (graph-wanted (option-ref options 'graph #f))
  131. (number-wanted (option-ref options 'number #f))
  132. (set-wanted (option-ref options 'set #f)))
  133. (if (or number-wanted version-wanted help-wanted set-wanted graph-wanted)
  134. (cond
  135. (version-wanted
  136. (display "collatz version 0.1\n"))
  137. (help-wanted
  138. (display "collatz [options]\n")
  139. (display "")
  140. (display "-v --version Display version\n")
  141. (display "-h, --help Display this help info\n")
  142. (display "-g, --graph Graph the set of numbers' iterations via gnuplot\n")
  143. (display " ie: collatz -g 500\n")
  144. (display "-n, --number Returns the number of iterations required to turn this number to 1\n")
  145. (display "-s, --set Specify a set of numbers, to which to apply the 3 + 1 formula.\n")
  146. (display " ie: collatz -s 500 will return the number which requires the most\n")
  147. (display " iterations in the set of numbers 2-500\n")
  148. )
  149. (number-wanted
  150. (display (collatz (string->number number-wanted)))
  151. (display "\n"))
  152. (set-wanted
  153. (let ((result (collatz-set (string->number set-wanted))))
  154. (display "In the set of 2-")
  155. (display set-wanted)
  156. (display " ")
  157. (display (car result))
  158. (display " has the most iterations with ")
  159. (display (car (cdr result)))
  160. (display " iterations\n")))
  161. (graph-wanted
  162. (graph-collatz-set (string->number graph-wanted)))))))