;;;; -*- Mode: Lisp; Base: 10; Syntax: ANSI-Common-Lisp; Package: cl-user; Coding: utf-8 -*-
;;;; Copyright © 2025 David Mullen. License: Zero-Clause BSD. Origin:
(in-package :cl-user)
(defun get-weyl-seed ()
(with-open-file (stream "/dev/urandom" :element-type '(unsigned-byte 64))
;; From : "The increment S must be odd to ensure
;; the maximum period of the Weyl sequence. All the other variables can be initialized
;; by using any number. We suggest seeding S by an odd number and setting all other
;; elements to zero for the sake of simplicity, in single-stream applications."
(logior (the (unsigned-byte 64) (read-byte stream)) 1)))
(defun make-cwg64 (&optional (x 0) (a 0) (weyl 0) (s (get-weyl-seed)))
"Construct and initialize 64-bit Collatz-Weyl Generator function."
(macrolet ((collatz^weyl ()
;; "The main types of transformations performed by the original Collatz
;; function are bitwise shifts of the state by 1 bit or the additions
;; of a number to it followed by a bitwise shift. All three proposed
;; Collatz-Weyl Generators above also contain this transformation,
;; which induces arithmetical chaos when combined with multiplication.
;; Using bitwise OR with the number 1 on one of the factors gives
;; slightly better statistical results, according to our experiments."
`(logxor (ldb (byte 64 0) (* (ash x -1) (logior a 1))) weyl))
(step-collatz-weyl-generator ()
`(setq a (ldb (byte 64 0) (+ a x))
weyl (ldb (byte 64 0) (+ weyl s))
x (ldb (byte 64 0) (collatz^weyl)))))
;; "In multi-stream applications, to ensure the complete independence of the 264 streams,
;; the first 48 and 96 states of each stream should be skipped in the CWG64 and CWG128-64,
;; and the CWG128 generators, respectively. Otherwise, minor correlations may occur in the
;; first outputs of the successively initialized streams, especially if they are initialized
;; by using the numbers 1, 3, 5, ... or another counter."
(loop repeat 48 do (step-collatz-weyl-generator)
finally (return (lambda ()
(step-collatz-weyl-generator)
;; "In each generator, the lower bits of X are XORed
;; with the upper bits of A in the output scrambler,
;; due to the fact that the lower bits of X do not
;; have sufficient statistical quality."
(logxor (ash a -48) x))))))