2 ;; Maxima bit functions
3 ;; Copyright (C) 2008 Volker van Nek
5 ;; This source code is licensed under the terms of the Lisp Lesser
6 ;; GNU Public License (LLGPL). The LLGPL consists of a preamble, published
7 ;; by Franz Inc. (http://opensource.franz.com/preamble.html), and the GNU
8 ;; Library General Public License (LGPL), version 2, or (at your option)
9 ;; any later version. When the preamble conflicts with the LGPL,
10 ;; the preamble takes precedence.
12 ;; This library is distributed in the hope that it will be useful,
13 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
14 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 ;; Library General Public License for details.
17 ;; You should have received a copy of the GNU Library General Public
18 ;; License along with this library; if not, write to the
19 ;; Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
20 ;; Boston, MA 02110-1301, USA.
23 ;; functions at Maxima level:
25 ;; bit_not bitwise NOT
26 ;; bit_and bitwise AND
27 ;; bit_xor bitwise XOR
29 ;; bit_lsh bitwise LEFT SHIFT
30 ;; bit_rsh bitwise RIGHT SHIFT
32 ;; bit_length number of necessary bits to represent a positive integer
33 ;; bit_onep test for bit 1
36 ;; comments in this file use the following abbreviations:
37 ;; i,j,k : literal integers
38 ;; x,y,z : any expression
39 ;; di,dj,dk : declared integer
40 ;; de, do : declared even resp. odd
44 (macsyma-module bitwise
)
48 (:compile-toplevel
:execute
)
49 (defvar old-ibase
*read-base
*)
50 (setq *read-base
* 10.
) )
53 ;; I'm not sure if we should add the property 'integer-valued to these functions
54 ;; if we allow bit_not(bit_not(x)) --> x, bit_and(x) --> x, etc. for any expression x
55 (setf (get '$bit_not
'integer-valued
) t
)
56 (setf (get '$bit_and
'integer-valued
) t
)
57 (setf (get '$bit_xor
'integer-valued
) t
)
58 (setf (get '$bit_or
'integer-valued
) t
)
59 (setf (get '$bit_lsh
'integer-valued
) t
)
60 (setf (get '$bit_rsh
'integer-valued
) t
)
61 (setf (get '$bit_length
'integer-valued
) t
)
65 ;; ERROR if at least one arg to bit_function is a non-integer constant, string or Maxima list
67 (defun badargcheck (a f n
)
68 (if (or (and (not (integerp a
)) ($constantp a
))
71 (let ((s (format nil
"bad ~@[~:r~] argument to `~a': ~a" n f
($sconcat a
))))
78 (defprop $bit_not simp-bit-not operators
)
80 (defun simp-bit-not (a tmp z
)
81 (declare (ignore tmp
))
83 (setq a
(simplifya (cadr a
) z
))
84 (badargcheck a
"bit_not" nil
)
85 (cond ((integerp a
) ;; bit_not(i) --> bitwise NOT i
87 ((and (listp a
) (listp (car a
)) (equal (caar a
) '$bit_not
))
88 (cadr a
)) ;; bit_not(bit_not(x)) --> x ;; di instead of x ?
89 ((maxima-integerp a
) ;; bit_not(di) --> - di - 1
90 (meval `((mplus) ((mminus) ,a
) -
1)))
92 `(($bit_not simp
) ,a
)) )) ;; return unevaluated
98 (defprop $bit_and simp-bit-and operators
)
100 (defun simp-bit-and (args tmp z
)
101 (declare (ignore tmp
))
102 (setq args
(cdr args
))
104 ;; trivial case bit_and() --> -1
105 (if (null args
) (return-from simp-bit-and -
1))
107 (let ((acc nil
) (n 1) (ints nil
))
109 ;; check and simplify the arguments
111 (badargcheck a
"bit_and" n
)
113 (push (simplifya a z
) acc
) )
115 ;; separate the arguments into a list of literal integers and the rest
116 ;; and remove duplicates bit_and(x,x,y) --> bit_and(x,y)
117 (setq args
(sorted-remove-duplicates (sort acc
'$orderlessp
)))
119 ((or (null args
) (not (integerp a
))))
121 (setq args
(cdr args
))
122 (setq a
(car args
)) )
124 ;; apply logand to the list of literal integers and return if possible
125 (setq n
(apply #'logand ints
))
126 (if (null args
) (return-from simp-bit-and n
)) ;; bit_and(i,j) --> bitwise i AND j
127 (cond ((zerop n
) (return-from simp-bit-and
0)) ;; bit_and(0,x) --> 0
128 ((= n -
1) (setq ints nil
)) ;; bit_and(-1,x) --> bit_and(x) ( --> x see below )
129 (t (setq ints
(list n
)))) ;; bit_and(i,j,x) --> bit_and(bit_and(i,j),x)
131 ;; if twos complement occurs bit_and(x,bit_not(x),y) --> 0
134 ((null (cdr args
)) (push a acc
))
135 (if (some #'(lambda (b) (equal t
(meval `(($is
) (($equal
) (($bit_not simp
) ,a
) ,b
))))) (cdr args
))
136 (return-from simp-bit-and
0))
138 (setq args
(cdr args
))
139 (setq a
(car args
)) )
141 ;; even or odd declared objects bit_and(1,de,y) --> 0
142 (if (and (= n
1) (some #'(lambda (b) ($featurep b
'$even
)) acc
))
143 (return-from simp-bit-and
0))
144 ;; bit_and(1,do) --> 1
145 (if (and (= n
1) (every #'(lambda (b) ($featurep b
'$odd
)) acc
))
146 (return-from simp-bit-and
1))
148 ;; if one arg remains bit_and(x) --> x ;; di instead of x ?
149 (setq args
(append ints
(reverse acc
)))
150 (if (= 1 (length args
))
151 ;;(and (= 1 (length args)) (maxima-integerp (car args))); if we require bit_and(di) --> di
152 (return-from simp-bit-and
(car args
)))
154 ;; return unevaluated if no previous return-from occurred
155 `(($bit_and simp
) ,@args
)))
159 ;; helpers for $bit_xor
161 (defun sorted-remove-pairs (l)
162 (do ((a (car l
) (car l
)) (acc nil
))
163 ((null l
) (reverse acc
))
164 (cond ((and (cdr l
) (like a
(cadr l
)))
167 (setq l
(cdr l
))) )))
169 (defun remove-twos-complement (n l
)
170 (do ((a (car l
) (car l
)) (acc nil
))
171 ((null l
) (reverse acc
))
172 (cond ((equal t
(meval `(($is
) (($equal
) (($bit_not
) ,a
) ,n
))))
173 (return-from remove-twos-complement
(append (reverse acc
) (cdr l
))))
175 (setq l
(cdr l
))) )))
179 ;; bitwise EXCLUSIVE OR
181 (defprop $bit_xor simp-bit-xor operators
)
183 (defun simp-bit-xor (args tmp z
)
184 (declare (ignore tmp
))
185 (setq args
(cdr args
))
187 ;; trivial case bit_xor() --> 0
188 (if (null args
) (return-from simp-bit-xor
0))
190 (let ((acc nil
) (n 1) (ints nil
))
192 ;; check and simplify the arguments
194 (badargcheck a
"bit_xor" n
)
196 (push (simplifya a z
) acc
) )
198 ;; separate the arguments into a list of literal integers and the rest
199 ;; and remove pairs bit_xor(x,x,y,z) --> bit_xor(y,z)
201 (setq args
(sorted-remove-pairs (sort acc
'$orderlessp
)))
203 ((or (null args
) (not (integerp a
))))
205 (setq args
(cdr args
))
206 (setq a
(car args
)) )
208 ;; apply logxor to the list of integers and return if possible
209 (setq n
(apply #'logxor ints
))
210 (if (null args
) (return-from simp-bit-xor n
)) ;; bit_xor(i,j) --> bitwise i XOR j
211 (setq ints
(list n
)) ;; bit_xor(i,j,x) --> bit_xor(bit_xor(i,j),x)
213 ;; if twos complement occurs bit_xor(x,bit_not(x),y,z) --> bit_xor(-1,y,z)
216 ((null (cdr args
)) (and a
(push a acc
)))
217 (cond ((some #'(lambda (b) (equal t
(meval `(($is
) (($equal
) (($bit_not
) ,a
) ,b
))))) (cdr args
))
218 (rplacd args
(remove-twos-complement a
(cdr args
)))
219 (setq ints
(list (setq n
(1- (- n
))))))
221 (setq args
(cdr args
))
222 (setq a
(car args
)) )
223 (setq acc
(reverse acc
))
225 ;; n might have been changed in previous step; 0 occurs
226 (if (zerop n
) (setq ints nil
)) ;; bit_xor(0,x) --> bit_xor(x) ( --> x see below)
228 ;; if there is an even or odd declared object bit_xor(1,de,y) --> bit_xor(de+1,y) --> recurse
229 (if (and (= n
1) (some #'(lambda (b) ($featurep b
'$even
)) acc
))
231 (do ((a (car acc
) (car acc
)) (bcc nil
))
232 ((null acc
) (setq acc
(reverse bcc
)))
233 (if ($featurep a
'$even
)
235 (setq acc
(append (reverse bcc
) (list (meval `((mplus) ,a
1))) (cdr acc
)))
238 (return-from simp-bit-xor
(meval `(($bit_xor simp
) ,@acc
))) ))
240 (setq acc
(cdr acc
))) ))
241 ;; bit_xor(1,do,y) --> bit_xor(do-1,y) --> recurse
242 (if (and (= n
1) (some #'(lambda (b) ($featurep b
'$odd
)) acc
))
244 (do ((a (car acc
) (car acc
)) (bcc nil
))
245 ((null acc
) (setq acc
(reverse bcc
)))
246 (if ($featurep a
'$odd
)
248 (setq acc
(append (reverse bcc
) (list (meval `((mplus) ,a
((mminus) 1)))) (cdr acc
)))
251 (return-from simp-bit-xor
(meval `(($bit_xor simp
) ,@acc
))) ))
253 (setq acc
(cdr acc
))) ))
255 ;; -1 occurs bit_xor(-1,x,y) --> bit_xor(bit_not(x),y) --> recurse
256 (if (and acc
(= n -
1))
257 (return-from simp-bit-xor
258 (meval `(($bit_xor simp
)
259 ,@(cons (meval `(($bit_not simp
) ,(car acc
))) (cdr acc
)) )) ))
261 ;; if one arg remains bit_xor(x) --> x ;; di instead of x ?
262 (setq args
(append ints acc
))
263 (if (= 1 (length args
))
264 (return-from simp-bit-xor
(car args
)))
266 ;; return unevaluated if no previous return-from occurred
267 `(($bit_xor simp
) ,@args
)))
273 (defprop $bit_or simp-bit-or operators
)
275 (defun simp-bit-or (args tmp z
)
276 (declare (ignore tmp
))
277 (setq args
(cdr args
))
279 ;; trivial case bit_or() --> 0
280 (if (null args
) (return-from simp-bit-or
0))
282 (let ((acc nil
) (n 1) (ints nil
))
284 ;; check and simplify the arguments
286 (badargcheck a
"bit_or" n
)
288 (push (simplifya a z
) acc
) )
290 ;; separate the arguments into a list of literal integers and the rest
291 ;; and remove duplicates bit_or(x,x,y) --> bit_or(x,y)
292 (setq args
(sorted-remove-duplicates (sort acc
'$orderlessp
)))
294 ((or (null args
) (not (integerp a
))))
296 (setq args
(cdr args
))
297 (setq a
(car args
)) )
299 ;; apply logior to the list of literal integers and return if possible
300 (setq n
(apply #'logior ints
))
301 (if (null args
) (return-from simp-bit-or n
)) ;; bit_or(i,j) --> bitwise i OR j
302 (cond ((= n -
1) (return-from simp-bit-or -
1)) ;; bit_or(-1,x) --> -1
303 ((zerop n
) (setq ints nil
)) ;; bit_or(0,x) --> bit_or(x) ( --> x see below)
304 (t (setq ints
(list n
)))) ;; bit_or(i,j,x) --> bit_or(bit_or(i,j),x)
306 ;; if twos complement occurs bit_or(x,bit_not(x),y) --> -1
309 ((null (cdr args
)) (push a acc
))
310 (if (some #'(lambda (b) (equal t
(meval `(($is
) (($equal
) (($bit_not simp
) ,a
) ,b
))))) (cdr args
))
311 (return-from simp-bit-or -
1))
313 (setq args
(cdr args
))
314 (setq a
(car args
)) )
316 ;; if there is an even or odd declared obj bit_or(1,de,y) --> bit_or(de+1,y) --> recurse
317 (if (and (= n
1) (some #'(lambda (b) ($featurep b
'$even
)) acc
))
319 (do ((a (car acc
) (car acc
)) (bcc nil
))
320 ((null acc
) (setq acc
(reverse bcc
)))
321 (if ($featurep a
'$even
)
323 (setq acc
(append (reverse bcc
) (list (meval `((mplus) ,a
1))) (cdr acc
)))
326 (return-from simp-bit-or
(meval `(($bit_or simp
) ,@acc
))) ))
328 (setq acc
(cdr acc
))) ))
329 ;; bit_or(1,do,y) --> bit_or(do,y)
330 (if (and (= n
1) (some #'(lambda (b) ($featurep b
'$odd
)) acc
))
333 ;; if one arg remains bit_or(x) --> x ;; di instead of x ?
334 (setq args
(append ints
(reverse acc
)))
335 (if (= 1 (length args
))
336 (return-from simp-bit-or
(car args
)))
338 ;; return unevaluated if no previous return-from occurred
339 `(($bit_or simp
) ,@args
)))
343 ;; bitwise LEFT SHIFT
345 (defprop $bit_lsh simp-bit-lsh operators
)
347 (defun simp-bit-lsh (e tmp z
)
348 (declare (ignore tmp
))
350 (let ((a (simplifya (cadr e
) z
))
351 (count (simplifya (caddr e
) z
)))
352 (badargcheck a
"bit_lsh" 1)
353 (badargcheck count
"bit_lsh" 2)
354 (cond ((and (integerp a
) (integerp count
)) ;; bit_lsh(i,k) --> bitwise LEFT SHIFT i,k
356 ((and (maxima-integerp count
) (equal (meval `(($is
) ((mgeqp) ,count
0))) t
))
357 (meval `((mtimes) ((mexpt) 2 ,count
) ,a
))) ;; bit_lsh(x,dk) --> 2^dk*x, where dk>=0 ;; di instead of x ?
359 `(($bit_lsh simp
) ,a
,count
)) ))) ;; return unevaluated
363 ;; bitwise RIGHT SHIFT
365 (defprop $bit_rsh simp-bit-rsh operators
)
367 (defun simp-bit-rsh (e tmp z
)
368 (declare (ignore tmp
))
370 (let ((a (simplifya (cadr e
) z
))
371 (count (simplifya (caddr e
) z
)))
372 (badargcheck a
"bit_rsh" 1)
373 (badargcheck count
"bit_rsh" 2)
374 (meval `(($bit_lsh
) ,a
(- ,count
))))) ;; bit_rsh(x,y) --> bit_lsh(x,-y)
380 (defprop $bit_onep simp-bit-onep operators
)
382 (defun simp-bit-onep (e tmp z
)
383 (declare (ignore tmp
))
385 (let ((a (simplifya (cadr e
) z
))
386 (index (simplifya (caddr e
) z
)))
387 (badargcheck a
"bit_onep" 1)
388 (badargcheck index
"bit_onep" 2)
389 (if (equal t
(meval `(($is
) ((mlessp) ,index
0)))) ;; additional check: error if index<0
390 (merror "second argument to `bit_onep' must be non-negative."))
391 (cond ((and (integerp a
) (integerp index
)) ;; bit_onep(i,k) --> ONE-BIT TEST i,k, k>=0
394 (cond (($featurep a
'$even
) nil
) ;; bit_onep(de,0) --> false
395 (($featurep a
'$odd
) t
))) ;; bit_onep(do,0) --> true
396 ((and (maxima-integerp index
) ;; bit_onep(x,dk) where 0<=x<2^dk, dk>=0 --> false
397 (equal t
(meval `(($is
) ((mgeqp) ,index
0))))
398 (equal t
(meval `(($is
) ((mgeqp) ,a
0))))
399 (equal t
(meval `(($is
) ((mlessp) ,a
((mexpt) 2 ,index
))))))
401 ((and ;; bit_onep(di^dj,y) where di^dj = 2^y --> true
402 (listp a
) (listp (car a
)) (equal (caar a
) 'mexpt
)
403 ;; check if y = dj*log(di)/log(2) :
404 (maxima-integerp (cadr a
))
405 (maxima-integerp (caddr a
))
407 (meval `(($is
) (($equal
)
409 ((mquotient) ((mtimes) ,(caddr a
) ((%log
) (($factor
) ,(cadr a
)))) ((%log
) 2)) )))))
412 `(($bit_onep simp
) ,a
,index
)) ))) ;; return unevaluated
418 (defprop $bit_length simp-bit-length operators
)
420 (defun simp-bit-length (a tmp z
)
421 (declare (ignore tmp
))
423 (setq a
(simplifya (cadr a
) z
))
424 (badargcheck a
"bit_length" nil
)
425 (if (equal t
(meval `(($is
) ((mlessp) ,a
0)))) ;; additional check: error if a<0
426 (merror "argument to `bit_length' must be non-negative."))
427 (cond ((integerp a
) ;; bit_length(i) --> BIT LENGTH i
429 ((and ;; bit_length(2^dk) --> dk+1, bit_length(4^dk) --> 2*dk+1, etc.
431 (listp a
) (listp (car a
)) (equal (caar a
) 'mexpt
)
432 (maxima-integerp (cadr a
))
433 (maxima-integerp (caddr a
)) (equal t
(meval `(($is
) ((mgeqp) ,(caddr a
) 0))))
434 (let ((fl (get-factor-list (cadr a
))) e
)
435 (and (= 1 (length fl
)) (= 2 (caar fl
)))
437 (return-from simp-bit-length
(meval `((mplus) ((mtimes) ,e
,(caddr a
)) 1)) ))))
439 `(($bit_length simp
) ,a
)) )) ;; return unevaluated
443 (:compile-toplevel
:execute
)
444 (setq *read-base
* old-ibase
) )