-
Notifications
You must be signed in to change notification settings - Fork 20
/
zeta-integer.lisp
157 lines (146 loc) · 6.72 KB
/
zeta-integer.lisp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
(defpackage :cp/zeta-integer
(:use :cl)
(:export #:divisor-transform! #:inverse-divisor-transform!
#:multiple-transform! #:inverse-multiple-transform!)
(:documentation "Provides fast zeta/Moebius transforms w.r.t. divisor or
multiple. Time complexity is O(nloglog(n))."))
(in-package :cp/zeta-integer)
(declaim (inline divisor-transform!))
(defun divisor-transform! (vector &optional (op+ #'+) (handle-zero t))
"Sets each VECTOR[i] to the sum of VECTOR[d] for all the divisors d of
i. Ignores VECTOR[0] when HANDLE-ZERO is NIL."
(declare (vector vector))
(let* ((n (length vector))
(sieve (make-array n :element-type 'bit :initial-element 1)))
(when handle-zero
(loop for i from 1 below n
do (setf (aref vector 0)
(funcall op+ (aref vector 0) (aref vector i)))))
(loop for p from 2 below n
when (= 1 (sbit sieve p))
do (loop for k from 1 below (ceiling n p)
for pmult of-type fixnum = (* k p)
do (setf (sbit sieve pmult) 0)
(setf (aref vector pmult)
(funcall op+ (aref vector pmult) (aref vector k)))))
vector))
(declaim (inline inverse-divisor-transform!))
(defun inverse-divisor-transform! (vector &optional (op- #'-) (handle-zero t))
"Does the inverse transform of DIVISOR-TRANSFORM!. Ignores VECTOR[0] when
HANDLE-ZERO is NIL."
(declare (vector vector))
(let* ((n (length vector))
(sieve (make-array n :element-type 'bit :initial-element 1)))
(loop for p from 2 below n
when (= 1 (sbit sieve p))
do (loop for k from (- (ceiling n p) 1) downto 1
for pmult of-type fixnum = (* k p)
do (setf (sbit sieve pmult) 0)
(setf (aref vector pmult)
(funcall op- (aref vector pmult) (aref vector k)))))
(when handle-zero
(loop for i from 1 below n
do (setf (aref vector 0)
(funcall op- (aref vector 0) (aref vector i)))))
vector))
(declaim (inline multiple-transform!))
(defun multiple-transform! (vector &optional (op+ #'+) (handle-zero t))
"Sets each VECTOR[i] to the sum of VECTOR[m] for all the multiples m of i. (To
be precise, all the multiples smaller than the length of VECTOR.) Ignores
VECTOR[0] when HANDLE-ZERO is NIL."
(declare (vector vector))
(let* ((n (length vector))
(sieve (make-array n :element-type 'bit :initial-element 1)))
(loop for p from 2 below n
when (= 1 (sbit sieve p))
do (loop for k from (- (ceiling n p) 1) downto 1
for pmult of-type fixnum = (* k p)
do (setf (sbit sieve pmult) 0)
(setf (aref vector k)
(funcall op+ (aref vector k) (aref vector pmult)))))
(when handle-zero
(loop for i from 1 below n
do (setf (aref vector i)
(funcall op+ (aref vector 0) (aref vector i)))))
vector))
(declaim (inline inverse-multiple-transform!))
(defun inverse-multiple-transform! (vector &optional (op- #'-) (handle-zero t))
"Does the inverse transform of MULTIPLE-TRANSFORM!. Ignores VECTOR[0] when
HANDLE-ZERO is NIL."
(declare (vector vector))
(let* ((n (length vector))
(sieve (make-array n :element-type 'bit :initial-element 1)))
(when handle-zero
(loop for i from 1 below n
do (setf (aref vector i)
(funcall op- (aref vector i) (aref vector 0)))))
(loop for p from 2 below n
when (= 1 (sbit sieve p))
do (loop for k from 1 below (ceiling n p)
for pmult of-type fixnum = (* k p)
do (setf (sbit sieve pmult) 0)
(setf (aref vector k)
(funcall op- (aref vector k) (aref vector pmult)))))
vector))
;;;
;;; (Slower) Zeta/Moebius transforms w.r.t. divisor or multiple in O(nlog(n)) time
;;;
;; (declaim (inline divisor-transform!))
;; (defun divisor-transform! (vector &optional (op+ #'+) (handle-zero t))
;; "Sets each VECTOR[i] to the sum of VECTOR[d] for all the divisors d of i in
;; O(nlog(n)) time."
;; (declare (vector vector))
;; (let ((n (length vector)))
;; (when handle-zero
;; (loop for i from 1 below n
;; do (setf (aref vector 0)
;; (funcall op+ (aref vector 0) (aref vector i)))))
;; (loop for i from (- (ceiling n 2) 1) downto 1
;; do (loop for j from (+ i i) below n by i
;; do (setf (aref vector j)
;; (funcall op+ (aref vector i) (aref vector j)))))
;; vector))
;; (declaim (inline inverse-divisor-transform!))
;; (defun inverse-divisor-transform! (vector &optional (op- #'-) (handle-zero t))
;; "Does the inverse transform of DIVISOR-TRANSFORM! in O(nlog(n)) time."
;; (declare (vector vector))
;; (let ((n (length vector)))
;; (loop for i from 1 below (ceiling n 2)
;; do (loop for j from (+ i i) below n by i
;; do (setf (aref vector j)
;; (funcall op- (aref vector j) (aref vector i)))))
;; (when handle-zero
;; (loop for i from 1 below n
;; do (setf (aref vector 0)
;; (funcall op- (aref vector 0) (aref vector i)))))
;; vector))
;; (declaim (inline multiple-transform!))
;; (defun multiple-transform! (vector &optional (op+ #'+) (handle-zero t))
;; "Sets each VECTOR[i] to the sum of VECTOR[m] for all the multiples m of i in
;; O(nlog(n)) time. (To be precise, all the multiples smaller than the length of
;; VECTOR.)"
;; (declare (vector vector))
;; (let ((n (length vector)))
;; (loop for i from 1 below (ceiling n 2)
;; do (loop for j from (+ i i) below n by i
;; do (setf (aref vector i)
;; (funcall op+ (aref vector i) (aref vector j)))))
;; (when handle-zero
;; (loop for i from 1 below n
;; do (setf (aref vector i)
;; (funcall op+ (aref vector 0) (aref vector i)))))
;; vector))
;; (declaim (inline inverse-multiple-transform!))
;; (defun inverse-multiple-transform! (vector &optional (op- #'-) (handle-zero t))
;; "Does the inverse transform of MULTIPLE-TRANSFORM! in O(nlog(n)) time."
;; (declare (vector vector))
;; (let ((n (length vector)))
;; (when handle-zero
;; (loop for i from 1 below n
;; do (setf (aref vector i)
;; (funcall op- (aref vector i) (aref vector 0)))))
;; (loop for i from (- (ceiling n 2) 1) downto 1
;; do (loop for j from (+ i i) below n by i
;; do (setf (aref vector i)
;; (funcall op- (aref vector i) (aref vector j)))))
;; vector))