src/4d/polydivisible-numbers.lisp @ 4b54adfbaf3d default tip

More refactoring
author Steve Losh <steve@stevelosh.com>
date Tue, 24 Dec 2019 13:50:19 -0500
parents (none)
children (none)
(defpackage :euler/4d/polydivisible-numbers #.euler:*use*)
(in-package :euler/4d/polydivisible-numbers)

(setf lparallel:*kernel* (lparallel:make-kernel 30))

(deftype radix ()
  '(integer 2 64))

(deftype digit ()
  '(integer 1 63))

(deftype digit-set ()
  '(unsigned-byte 63))

(defun make-digits (radix)
  (1- (expt 2 (1- radix))))

(defun-inline remove-digit (d digits)
  (declare (optimize speed)
           (type digit d)
           (type digit-set digits))
  (dpb 0 (byte 1 (1- d)) digits))

(defun new-candidates (radix candidate remaining)
  (declare (optimize speed)
           (type radix radix)
           (type digit-set remaining)
           (type (integer 0) candidate))
  (iterate
    (declare (iterate:declare-variables)
             (type (or (integer 0) digit) d)
             (type digit-set n more))
    (for d :from 1)
    (for n :first remaining :then more)
    (for (values more d?) = (truncate n 2))
    (unless (zerop d?)
      (collect (cons (+ (* radix candidate) d)
                     (remove-digit d remaining))))
    (until (zerop more))))

(defun find-polydivisible-numbers (radix)
  (labels ((recur (n candidate remaining)
             (when (or (zerop n) (dividesp candidate n))
               (if (= n (1- radix))
                 (list candidate)
                 (funcall (if (< n 2)
                            #'lparallel:pmapcan
                            ;; #'mapcan
                            #'mapcan
                            )
                          (lambda (next)
                            (recur (1+ n) (car next) (cdr next)))
                          (new-candidates radix candidate remaining))))))
    (cons radix (recur 0 0 (make-digits radix)))))