1 ;;;; lsbasics -- Low level Lisp-Stat functions
3 ;;;; Copyright (c) 1991, by Luke Tierney. Permission is granted for
14 (defpackage "LISP-STAT-BASICS"
15 (:nicknames
"LS-BASICS")
16 (:use
"COMMON-LISP" "LISP-STAT-OBJECT-SYSTEM"))
18 (in-package lisp-stat-basics
))
20 (in-package 'lisp-stat-basics
21 :nicknames
'(ls-basics)
24 (shadowing-import (package-shadowing-symbols 'lisp-stat-object-system
))
26 (use-package 'lisp-stat-object-system
)
28 (export '(sequencep copy-vector copy-array iseq which repeat select
29 permute-array sum prod count-elements mean if-else
30 sample sort-data order rank
))
32 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
34 ;;;; Type Checking Functions
36 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
40 Returns T if X is a fixnum; NIL otherwise."
41 (declare (inline typep
))
44 (defun check-nonneg-fixnum (x)
45 (if (and (fixnump x
) (<= 0 x
)) x
(error "not a non-negative fixnum")))
47 (defun check-one-fixnum (x)
48 (if (not (fixnump x
)) (error "not a fixnum - ~a" x
)))
50 (defun check-one-real (a)
51 (if (not (or (rationalp a
) (floatp a
))) (error "not a real number ~s" a
)))
53 (defun check-one-number (a)
54 (if (not (numberp a
)) (error "not a number ~s" a
)))
56 (defun check-sequence (a)
57 (if (not (or (vectorp a
) (consp a
))) (error "not a sequence - ~s" a
)))
59 (defun check-matrix (a)
60 (if (not (and (arrayp a
) (= (array-rank a
) 2)))
61 (error "not a matrix - ~s" a
)))
63 (defun check-square-matrix (a)
65 (let ((m (array-dimension a
0))
66 (n (array-dimension a
1)))
67 (if (/= n m
) (error "not a square matrix - ~s" a
))))
70 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
72 ;;;; Sequence Element Access
74 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
76 (defun get-next-element (x i
)
77 (let ((seq (first x
)))
79 (let ((elem (first seq
)))
80 (setf (first x
) (rest seq
))
84 (defun set-next-element (x i v
)
85 (let ((seq (first x
)))
88 (setf (first x
) (rest seq
)))
89 (t (setf (aref seq i
) v
)))))
91 (defun make-next-element (x) (list x
))
93 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
95 ;;;; Array to Row-Major Data Vector Conversion Functions
97 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
99 (defun array-data-vector (a)
101 Displaces array A to a vector"
102 (make-array (array-total-size a
) :displaced-to a
103 :element-type
(array-element-type a
)))
105 (defun vector-to-array (v dims
)
107 Displaces vector V to array with dimensions DIMS"
108 (make-array dims
:displaced-to v
:element-type
(array-element-type v
)))
111 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
113 ;;;; Copying Functions
115 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
118 ;;; COPY-VECTOR function
121 (defun copy-vector (x)
123 Returns a copy of the vector X"
127 ;;; COPY-ARRAY function
130 (defun copy-array (a)
132 Returns a copy of the array A"
133 (vector-to-array (copy-seq (array-data-vector a
)) (array-dimensions a
)))
136 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
138 ;;;; Sequence Functions
140 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
143 ;;; sequence predicate SEQUENCEP
148 Returns NIL unless X is a list or vector."
149 (or (listp x
) (vectorp x
)))
152 ;;; ISEQ - generate a sequence of consecutive integers from a to b
155 (defun iseq (a &optional b
)
156 "Args: (n &optional m)
157 With one argumant returns a list of consecutive integers from 0 to N - 1.
158 With two returns a list of consecutive integers from N to M.
159 Examples: (iseq 4) returns (0 1 2 3)
160 (iseq 3 7) returns (3 4 5 6 7)
161 (iseq 3 -3) returns (3 2 1 0 -1 -2 -3)"
163 (let ((n (+ 1 (abs (- b a
))))
166 (setq x
(cons (if (< a b
) (- b i
) (+ b i
)) x
))))
169 ((< a
0) (iseq (+ a
1) 0))
170 ((< 0 a
) (iseq 0 (- a
1))))))
178 Returns a list of the indices where elements of sequence X are not NIL."
179 (let ((x (list (compound-data-seq x
)))
182 (flet ((add-result (x)
183 (if result
(setf (rest tail
) (list x
)) (setf result
(list x
)))
184 (setf tail
(if tail
(rest tail
) result
)))
185 (get-next-element (seq-list i
)
186 (cond ((consp (first seq-list
))
187 (let ((elem (first (first seq-list
))))
188 (setf (first seq-list
) (rest (first seq-list
)))
190 (t (aref (first seq-list
) i
)))))
191 (let ((n (length (first x
))))
192 (dotimes (i n result
)
193 (if (get-next-element x i
) (add-result i
)))))))
201 Repeats VALS. If TIMES is a number and VALS is a non-null, non-array atom,
202 a list of length TIMES with all elements eq to VALS is returned. If VALS
203 is a list and TIMES is a number then VALS is appended TIMES times. If
204 TIMES is a list of numbers then VALS must be a list of equal length and
205 the simpler version of repeat is mapped down the two lists.
206 Examples: (repeat 2 5) returns (2 2 2 2 2)
207 (repeat '(1 2) 3) returns (1 2 1 2 1 2)
208 (repeat '(4 5 6) '(1 2 3)) returns (4 5 5 6 6 6)
209 (repeat '((4) (5 6)) '(2 3)) returns (4 4 5 6 5 6 5 6)"
210 (cond ((compound-data-p b
)
211 (let* ((reps (coerce (compound-data-seq (map-elements #'repeat a b
))
213 (result (first reps
))
214 (tail (last (first reps
))))
215 (dolist (next (rest reps
) result
)
217 (setf (rest tail
) next
)
218 (setf tail
(last next
))))))
219 (t (let* ((a (if (compound-data-p a
)
220 (coerce (compound-data-seq a
) 'list
)
223 (dotimes (i b result
)
224 (let ((next (copy-list a
)))
225 (if result
(setf (rest (last next
)) result
))
226 (setf result next
)))))))
228 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
230 ;;;; Subset Selection and Mutation Functions
232 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
234 ;;;; is x an ordered sequence of nonnegative positive integers?
235 (defun ordered-nneg-seq(x)
238 (cx (make-next-element x
))
241 (let ((elem (check-nonneg-fixnum (get-next-element cx i
))))
242 (if (> m elem
) (return nil
) (setf m elem
)))))))
244 ;;;; select or set the subsequence corresponding to the specified indices
245 (defun sequence-select(x indices
&optional
(values nil set-values
))
251 (declare (fixnum rlen dlen vlen
))
253 ;; Check the input data
255 (check-sequence indices
)
256 (if set-values
(check-sequence values
))
258 ;; Find the data sizes
259 (setf data
(if (ordered-nneg-seq indices
) x
(coerce x
'vector
)))
260 (setf dlen
(length data
))
261 (setf rlen
(length indices
))
263 (setf vlen
(length values
))
264 (if (/= vlen rlen
) (error "value and index sequences do not match")))
266 ;; set up the result/value sequence
270 (make-sequence (if (listp x
) 'list
'vector
) rlen
)))
272 ;; get or set the sequence elements */
275 (cr (make-next-element result
))
276 (ci (make-next-element indices
))
281 (declare (fixnum i j index
))
282 (setf index
(get-next-element ci i
))
283 (if (<= dlen index
) (error "index out of range - ~a" index
))
284 (let ((elem (get-next-element cr i
)))
291 ((not (and (< j index
) (consp nextx
))))
293 (setf nextx
(rest nextx
)))
294 (setf (first nextx
) elem
))
295 (t (setf (aref x index
) elem
)))))
297 (cr (make-next-element result
))
298 (ci (make-next-element indices
))
304 (declare (fixnum i j index
))
305 (setf index
(get-next-element ci i
))
306 (if (<= dlen index
) (error "index out of range - ~a" index
))
308 ((listp data
) ;; indices must be ordered
310 ((not (and (< j index
) (consp nextx
))))
312 (setf nextx
(rest nextx
)))
313 (setf elem
(first nextx
)))
314 (t (setf elem
(aref data index
))))
315 (set-next-element cr i elem
)))
319 ;;;; translate row major index in resulting subarray to row major index
320 ;;;; in the original array
321 ;;;;*** is the floor in this function really needed???
322 (defun old-rowmajor-index (index indices dim olddim
)
323 (declare (fixnum index
))
324 (let ((rank (length dim
))
328 (declare (fixnum rank face oldface
))
332 (setf face
(* face
(aref dim i
)))
333 (setf oldface
(* oldface
(aref olddim i
))))
337 (setf face
(/ face
(aref dim i
)))
338 (setf oldface
(/ oldface
(aref olddim i
)))
340 (* oldface
(aref (aref indices i
) (floor (/ index face
)))))
341 (setf index
(rem index face
)))
345 ;;;; extract or set subarray for the indices from a displaced array
346 (defun subarray-select (a indexlist
&optional
(values nil set_values
))
358 (declare (fixnum rank n
))
360 (if (or (sequencep a
) (not (arrayp a
))) (error "not an array - ~a" a
))
361 (if (not (listp indexlist
)) (error "bad index list - ~a" indices
))
362 (if (/= (length indexlist
) (array-rank a
))
363 (error "wrong number of indices"))
365 (setf indices
(coerce indexlist
'vector
))
367 (setf olddim
(coerce (array-dimensions a
) 'vector
))
369 ;; compute the result dimension vector and fix up the indices
370 (setf rank
(array-rank a
))
371 (setf dim
(make-array rank
))
374 (setf index
(aref indices i
))
375 (setf n
(aref olddim i
))
376 (setf index
(if (fixnump index
) (vector index
) (coerce index
'vector
)))
377 (setf k
(length index
))
380 (if (<= n
(check-nonneg-fixnum (aref index j
)))
381 (error "index out of bounds - ~a" (aref index j
)))
382 (setf (aref indices i
) index
))
383 (setf (aref dim i
) (length index
)))
385 ;; set up the result or check the values
386 (let ((dim-list (coerce dim
'list
)))
390 ((compound-data-p values
)
391 (if (or (not (arrayp values
)) (/= rank
(array-rank values
)))
392 (error "bad values array - ~a" values
))
393 (setf vdim
(coerce (array-dimensions values
) 'vector
))
396 (if (/= (aref vdim i
) (aref dim i
))
397 (error "bad value array dimensions - ~a" values
)))
398 (setf result values
))
399 (t (setf result
(make-array dim-list
:initial-element values
)))))
400 (t (setf result
(make-array dim-list
)))))
402 ;; compute the result or set the values
403 (setf data
(compound-data-seq a
))
404 (setf result_data
(compound-data-seq result
))
405 (setf n
(length result_data
))
408 (setf k
(old-rowmajor-index i indices dim olddim
))
409 (if (or (> 0 k
) (>= k
(length data
))) (error "index out of range"))
411 (setf (aref data k
) (aref result_data i
))
412 (setf (aref result_data i
) (aref data k
))))
420 (defun select (x &rest args
)
421 "Args: (a &rest indices)
422 A can be a list or an array. If A is a list and INDICES is a single number
423 then the appropriate element of A is returned. If is a list and INDICES is
424 a list of numbers then the sublist of the corresponding elements is returned.
425 If A in an array then the number of INDICES must match the ARRAY-RANK of A.
426 If each index is a number then the appropriate array element is returned.
427 Otherwise the INDICES must all be lists of numbers and the corresponding
428 submatrix of A is returned. SELECT can be used in setf."
430 ((every #'fixnump args
)
431 (if (listp x
) (nth (first args
) x
) (apply #'aref x args
)))
432 ((sequencep x
) (sequence-select x
(first args
)))
433 (t (subarray-select x args
))))
436 ;; Built in SET-SELECT (SETF method for SELECT)
437 (defun set-select (x &rest args
)
438 (let ((indices (butlast args
))
439 (values (first (last args
))))
442 (if (not (consp indices
)) (error "bad indices - ~a" indices
))
443 (let* ((indices (first indices
))
444 (i-list (if (fixnump indices
) (list indices
) indices
))
445 (v-list (if (fixnump indices
) (list values
) values
)))
446 (sequence-select x i-list v-list
)))
448 (subarray-select x indices values
))
449 (t (error "bad argument type - ~a" x
)))
452 (defsetf select set-select
)
455 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
457 ;;;; Array Permutation Functions
459 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
461 ;;;; permute x into y using perm; all should be vectors; If check is TRUE
462 ;;;; the routine will check to make sure no indices are reused, but x
463 ;;;; will be destroyed.
464 (defun permute-indices (x y perm check
)
465 (let ((rank (length x
)))
466 (declare (fixnum rank
))
469 (let ((k (aref perm i
)))
470 (if (not (fixnump k
)) (error "bad permutation sequence - ~a" perm
))
471 (if (or (< k
0) (>= k rank
))
472 (error "bad permutation sequence - ~a" perm
))
473 (setf (aref y i
) (aref x k
))
474 ;; to insure dimensions are not re-used
475 (if check
(setf (aref x k
) NIL
))))))
477 ;;;; compute indices in a from rowmajor index k, put in vector result
478 (defun indices-from-rowmajor (a k result
)
481 (if (not (arrayp a
)) (error "not an array - ~a" a
))
482 (if (or (> 0 k
) (>= k
(array-total-size a
))) (error "index out of range"))
485 (rank (array-rank a
))
486 (dim (array-dimensions a
)))
487 (declare (fixnum face rank
))
489 (let ((cdim (make-next-element dim
)))
492 (setf face
(* face
(get-next-element cdim i
)))))
494 (let ((cdim (make-next-element dim
)))
496 (setf face
(/ face
(get-next-element cdim i
)))
497 (setf (aref result i
) (floor (/ k face
)))
498 (setf k
(rem k face
))))))
500 ;;;; Translate row major index in original array to row major index in new
501 ;;;; array. Use indices vectors and ilist for temporary storage.
502 (defun translate-index (i result x perm indices oldindices ilist
)
504 (let ((rank (array-rank x
)))
505 (declare (fixnum rank
))
507 (indices-from-rowmajor x i oldindices
)
508 (permute-indices oldindices indices perm nil
)
510 (do ((next ilist
(rest next
))
512 ((not (and (< k rank
) (consp next
))))
513 (setf (first next
) (aref indices k
)))
515 (apply #'array-row-major-index result ilist
)))
518 ;;;; PERMUTE-ARRAY function
521 (defun permute-array (x perm
)
523 Returns a copy of the array A permuted according to the permutation P."
524 (if (not (arrayp x
)) (error "not an array - ~a" x
))
525 (check-sequence perm
)
526 (if (/= (length perm
) (array-rank x
))
527 (error "bad permutation sequence - ~a" perm
))
528 (let* ((perm (coerce perm
'vector
))
529 (rank (array-rank x
))
530 (dim (make-array rank
))
531 (olddim (coerce (array-dimensions x
) 'vector
)))
532 (declare (fixnum rank
))
534 ;; construct new dimension vector
535 (permute-indices olddim dim perm t
)
537 ;; make result array and the index vectors and lists */
538 (let* ((result (make-array (coerce dim
'list
)))
539 (indices (make-array rank
))
540 (oldindices (make-array rank
))
541 (ilist (make-list rank
))
542 (data (compound-data-seq x
))
543 (result_data (compound-data-seq result
))
549 (setf (aref oldindices i
) (list nil
)))
551 ;; fill in the result
552 (if (/= n
(length result_data
)) (error "bad data"))
553 (dotimes (i n result
)
555 (let ((k (translate-index i result x perm indices oldindices ilist
)))
557 (setf (aref result_data k
) (aref data i
)))))))
559 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
561 ;;;; SUM, PROD, COUNT-ELEMENTS, and MEAN Functions
563 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
568 (let ((seq (compound-data-seq x
))
572 (setf sum
(+ sum
(if (numberp x
) x
(sum-1 x
)))))
573 (let ((n (length seq
)))
577 (let ((x (aref seq i
)))
578 (setf sum
(+ sum
(if (numberp x
) x
(sum-1 x
)))))))))))
580 (defun sum (&rest args
)
581 "Args: (&rest number-data)
582 Returns the sum of all the elements of its arguments. Returns 0 if there
583 are no arguments. Vector reducing."
585 (sum-1 (if (rest args
) args
(first args
)))
591 (let ((seq (compound-data-seq x
))
595 (setf prod
(* prod
(if (numberp x
) x
(prod-1 x
)))))
596 (let ((n (length seq
)))
600 (let ((x (aref seq i
)))
601 (setf prod
(* prod
(if (numberp x
) x
(prod-1 x
)))))))))))
603 (defun prod (&rest args
)
604 "Args: (&rest number-data)
605 Returns the product of all the elements of its arguments. Returns 1 if there
606 are no arguments. Vector reducing."
608 (prod-1 (if (rest args
) args
(first args
)))
611 (defun count-elements (x)
612 "Args: (number &rest more-numbers)
613 Returns the number of its arguments. Vector reducing"
614 (if (compound-data-p x
)
615 (let ((seq (compound-data-seq x
))
618 (dolist (x seq count
)
619 (incf count
(if (compound-data-p x
) (count-elements x
) 1)))
620 (let ((n (length seq
)))
624 (let ((x (aref seq i
)))
625 (incf count
(if (compound-data-p x
) (count-elements x
) 1)))))))
630 Returns the mean of the elements x. Vector reducing."
633 (labels ((add-to-mean (x)
634 (let ((count+1 (+ count
1.0)))
635 (setf mean
(+ (* (/ count count
+1) mean
) (* (/ count
+1) x
)))
636 (setf count count
+1)))
640 (let ((seq (compound-data-seq x
)))
643 (if (numberp x
) (add-to-mean x
) (find-mean x
)))
644 (let ((n (length seq
)))
647 (let ((x (aref seq i
)))
650 (find-mean x
))))))))))
654 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
656 ;;;; Sorting Functions
658 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
662 Returns a sequence with the numbers or strings in the sequence X in order."
663 (flet ((less (x y
) (if (numberp x
) (< x y
) (string-lessp x y
))))
664 (stable-sort (copy-seq (compound-data-seq x
)) #'less
)))
668 Returns a sequence of the indices of elements in the sequence of numbers
669 or strings X in order."
670 (let* ((seq (compound-data-seq x
))
671 (type (if (consp seq
) 'list
'vector
))
673 (flet ((entry (x) (setf i
(+ i
1)) (list x i
))
677 (if (numberp x
) (< x y
) (string-lessp x y
)))))
678 (let ((sorted-seq (stable-sort (map type
#'entry seq
) #'less
)))
679 (map type
#'second sorted-seq
)))))
683 Returns a sequence with the elements of the list or array of numbers or
684 strings X replaced by their ranks."
685 (let ((ranked-seq (order (order x
))))
686 (make-compound-data (compound-data-shape x
) ranked-seq
)))
688 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
690 ;;;; IF-ELSE and SAMPLE Functions
692 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
694 (defun if-else (a x y
)
696 Takes simple or compound data items FIRST, X and Y and returns result of
697 elementswise selecting from X if FIRST is not NIL and from Y otherwise."
698 (flet ((base-if-else (a x y
) (if a x y
)))
699 (recursive-map-elements #'base-if-else
#'if-else a x y
)))
701 (defun sample (x ssize
&optional replace
)
702 "Args: (x n &optional (replace nil))
703 Returns a list of a random sample of size N from sequence X drawn with or
704 without replacement."
707 (x (if (consp x
) (coerce x
'vector
) (copy-vector x
)))
710 (dotimes (i ssize result
)
711 (let ((j (if replace
(random n
) (+ i
(random (- n i
))))))
712 (setf result
(cons (aref x j
) result
))
713 (unless replace
;; swap elements i and j
714 (let ((temp (aref x i
)))
715 (setf (aref x i
) (aref x j
))
716 (setf (aref x j
) temp
))))))))