Paste # 17456
2017-06-06 13:43:51

Fork as a new paste.

Paste viewed 38 times.


#lang racket

(define n 3)

;; If @term contains at least n r's in the front,
;; return (#f . rest-of-term).
;; If @term does not contain that many r's in the front,
;; return (#t . (r-part . rest-of-term)).
(define (seperate-adjacent-r term)
  (define (helper count r-list term)
    (if (null? term)
        (cons #t (cons r-list term))
        (if (eq? (car term) 'r)
            (if (= count (- n 1))
                (cons #f (cdr term))
                (helper (+ count 1) (cons 'r r-list) (cdr term)))
            (cons #t (cons r-list term)))))
  (helper 0 '() term))

(define (term-changed? term)
  (car term))
(define (get-term term)
  (cdr term))

(define (reduce-term term)
  (if (null? term)
      (cons #f '())
      ;; Term is not null
      (if (eq? (car term) 's)
          ;; First element is s
          (if (null? (cdr term))
              ;; Only element is s
              (cons #f term)
              ;; There is more to reduce after the s
              (if (eq? (cadr term) 's)
                  ;; First two elements are s's, cancel them
                  (cons #t (get-term (reduce-term (cddr term))))
                  ;; There is an s followed by an r
                  (let ([rest-reduced (reduce-term (cdr term))])
                    (if (term-changed? rest-reduced)
                        ;; If the following code after the s has changed, reduce some more
                        (cons #t (get-term (reduce-term (cons 's (get-term rest-reduced)))))
                        ;; Nothing changed, return result
                        (cons #f term)))))
          ;; First element is not s
          (let ([result (seperate-adjacent-r term)])
            (if (car result)
                ;; Not enough r's are present to cancel, look ahead of them
                (let ([rest-reduced (reduce-term (cddr result))])
                  (if (null? (get-term rest-reduced))
                      ;; Nothing is after the r's, return the result
                      (cons #f (cadr result))
                      (if (eq? (car (get-term rest-reduced)) 's)
                          ;; There is an s after the r, perform the sr transformation
                          (cons #t
                                (get-term (reduce-term (append (reverse (cdr (reverse (cadr result))))
                                                               (cons 's (build-list (- n 1) (lambda (x) 'r)))
                                                               (cdr (get-term rest-reduced))))))
                          ;; Only r's after the r, reduce some more
                          (cons (term-changed? rest-reduced)
                                  (append (cadr result)
                                          (get-term rest-reduced))))))))
                ;; We cancelled n r's, reduce the rest of the term
                (cons #t (get-term (reduce-term (cdr result)))))))))

(define (make-term x y)
  (define (helper x y result)
    (if (= y 0)
        (if (= x 0)
            (helper (- x 1) y (cons 's result)))
        (helper x (- y 1) (cons 'r result))))
  (helper x y '()))

;; Given an @n encoding a sum of terms, generate the actual list of terms in the sum
(define (number->term-sum num)
  (define (helper num result shift-count)
    (if (= num 0)
        (if (= (modulo num 2) 1)
            (helper (/ (- num 1) 2)
                    (cons (let ([x (if (< shift-count n)
                                [y (if (< shift-count n)
                                       (- shift-count n))])
                            (get-term (reduce-term (make-term x y))))
                    (+ shift-count 1))
            (helper (/ num 2) result (+ shift-count 1)))))
  (helper num '() 0))

;; Given two number @x and @y that encode two sums of terms,
;; multiply the sums together
(define (multiply-sums-of-terms x y)
  (let ([sumA (number->term-sum x)]
        [sumB (number->term-sum y)])
    (define (helper sum0 sum1 result)
      (if (null? sum0)
          (if (null? sum1)
              (helper (cdr sum0) sumB result)
              (helper sum0
                      (cdr sum1)
                      (cons (get-term
                              (append (car sum0)
                                      (car sum1))))
    (helper sumA sumB '())))

;; Given a @sum, encode the elements into numbers for easy use
(define (encode-sum sum)
  (define (encode-element e result)
    (if (null? e)
        (if (eq? (car e) 's)
            (encode-element (cdr e) (+ result n))
            (encode-element (cdr e) (+ result 1)))))
  (define (helper sum result)
    (if (null? sum)
        (helper (cdr sum)
                (cons (encode-element (car sum) 0)
  (helper sum '()))

;; Given an encoded sum of terms, tally up the terms
(define (tally-sum-terms sum)
  (define (helper result-table sum)
    (if (null? sum)
        (let ([num (car sum)])
          (vector-set! result-table
                       (+ (vector-ref result-table num) 1))
          (helper result-table (cdr sum)))))
  (helper (make-vector (* 2 n) 0) sum))

;; Given a tally table, reduce that table
(define (reduce-tally-table table)
  (for ([i (in-range 0 (* 2 n))])
    (vector-set! table
                 (modulo (vector-ref table i)

(define (product-equals-1? x y)
  (let ([product (multiply-sums-of-terms x y)])
    (let ([encoded-product (encode-sum product)])
      (let ([tally-table (tally-sum-terms encoded-product)])
        (let ([reduced-table (reduce-tally-table tally-table)])
          (define (scan-table table index)
            (if (= index (* 2 n))
                (if (= (vector-ref table 0) 1)
                (if (= (vector-ref table index) 1)
                    (scan-table table (+ index 1)))))
          (scan-table reduced-table 1))))))

;(product-equals-1? #b1011100 #b111)

(define count 0)
(for ([x (in-range 0 (expt 2 (* 2 n)))])
  (for ([y (in-range 0 (expt 2 (* 2 n)))])
    (if (product-equals-1? x y)
        (begin (printf "~x, ~x~n"
               (set! count (+ count 1)))
(display count)