include a real test csse in the examples -- former case was a bit wrong.
[CommonLispStat.git] / src / numerics / linalg.lsp
blob436a3edf2a2d93e8b6256cd76b8af7bdee021ffb
1 ;;; -*- mode: lisp -*-
2 ;;; Copyright (c) 2005--2008, by A.J. Rossini <blindglobe@gmail.com>
3 ;;; See COPYRIGHT file for any additional restrictions (BSD license).
4 ;;; Since 1991, ANSI was finally finished. Edited for ANSI Common Lisp.
5 ;;;
6 ;;; what this should do:
7 ;;; #2 - what to do for Fortran? Possibly: C <-> bridge, or CLapack?
8 ;;; problem: would be better to have access to Fortran. For
9 ;;; example, think of Doug Bates comment on reverse-calls (as
10 ;;; distinct from callbacks). It would be difficult if we don't
11 ;;; -- however, has anyone run Lapack or similar through F2CL?
12 ;;; Answer: yes, Matlisp does this.
13 ;;;
14 ;;; #3 - Use a lisp-based matrix system drop-in? (lisp-matrix, or ...
15 ;;; matlisp, femlisp, clem, ...?)
18 ;;;; linalg -- Lisp-Stat interface to basic linear algebra routines.
19 ;;;;
20 ;;;; Copyright (c) 1991, by Luke Tierney. Permission is granted for
21 ;;;; unrestricted use.
23 (in-package #:lisp-stat-linalg)
25 #+openmcl
26 (defctype size-t :unsigned-long)
27 #+sbcl
28 (defctype size-t :unsigned-int)
30 ;;; CFFI Support
32 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
33 ;;;
34 ;;; Lisp Interfaces to Linear Algebra Routines
35 ;;;
36 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
38 ;;;
39 ;;; Cholesky Decomposition
40 ;;;
42 (cffi:defcfun ("ccl_chol_decomp_front" ccl-chol-decomp-front)
43 :int (x :pointer) (y size-t) (z :pointer))
44 (defun chol-decomp-front (x y z)
45 (ccl-chol-decomp-front x y z))
47 ;;;;
48 ;;;; LU Decomposition
49 ;;;;
51 (cffi:defcfun ("ccl_lu_decomp_front" ccl-lu-decomp-front)
52 :int (x :pointer) (y size-t) (z :pointer) (u :int) (v :pointer))
53 (defun lu-decomp-front (x y z u v)
54 (ccl-lu-decomp-front x y z u v))
56 (cffi:defcfun ("ccl_lu_solve_front" ccl-lu-solve-front)
57 :int (x :pointer) (y size-t) (z :pointer) (u :pointer) (v :int))
58 (defun lu-solve-front (x y z u v)
59 (ccl-lu-solve-front x y z u v))
61 (cffi:defcfun ("ccl_lu_inverse_front" ccl-lu-inverse-front)
62 :int (x :pointer) (y size-t) (z :pointer) (u :pointer) (v :int) (w :pointer))
63 (defun lu-inverse-front (x y z u v w)
64 (ccl-lu-inverse-front x y z u v w))
66 ;;;;
67 ;;;; SV Decomposition
68 ;;;;
70 (cffi:defcfun ("ccl_sv_decomp_front" ccl-sv-decomp-front)
71 :int (x :pointer) (y size-t) (z size-t) (u :pointer) (v :pointer))
72 (defun sv-decomp-front (x y z u v)
73 (ccl-sv-decomp-front x y z u v))
75 ;;;;
76 ;;;; QR Decomposition
77 ;;;;
79 (cffi:defcfun ("ccl_qr_decomp_front" ccl-qr-decomp-front)
80 :int (x :pointer) (y size-t) (z size-t) (u :pointer) (v :pointer) (w :int))
81 (defun qr-decomp-front (x y z u v w)
82 (ccl-qr-decomp-front x y z u v w))
84 ;;;
85 ;;; Estimate of Condition Number for Lower Triangular Matrix
86 ;;;
88 (cffi:defcfun ("ccl_rcondest_front" ccl-rcondest-front)
89 :double (x :pointer) (y size-t))
90 (defun rcondest-front (x y)
91 (ccl-rcondest-front x y))
95 (defun rcondest-lisp-front (mat)
96 "Lisp-only version of rcondest."
97 (if (and (check-square-matrix mat)
98 (not (is-complex mat))) ;; Complex condition estimate not available
99 (if (= 0.0 (diag mat))
101 (let ((est (aref mat 0 0)))
102 (dotimes (j 0 n)
104 /* Set est to reciprocal of L1 matrix norm of A */
105 est = fabs(a[0][0]);
106 for (j = 1; j < n; j++) {
107 for (i = 0, temp = fabs(a[j][j]); i < j; i++)
108 temp += fabs(a[i][j]);
109 est = Max(est, temp);
111 est = 1.0 / est;
113 /* Solve A^Tx = e, selecting e as you proceed */
114 x[0] = 1.0 / a[0][0];
115 for (i = 1; i < n; i++) p[i] = a[0][i] * x[0];
116 for (j = 1; j < n; j++) {
117 /* select ej and calculate x[j] */
118 xp = ( 1.0 - p[j]) / a[j][j];
119 xm = (-1.0 - p[j]) / a[j][j];
120 temp = fabs(xp);
121 tempm = fabs(xm);
122 for (i = j + 1; i < n; i++) {
123 pm[i] = p[i] + a[j][i] * xm;
124 tempm += fabs(pm[i] / a[i][i]);
125 p[i] += a[j][i] * xp;
126 temp += fabs(p[i] / a[i][i]);
128 if (temp >= tempm) x[j] = xp;
129 else {
130 x[j] = xm;
131 for (i = j + 1; i < n; i++) p[i] = pm[i];
135 for (j = 0, xnorm = 0.0; j < n; j++) xnorm += fabs(x[j]);
136 est = est * xnorm;
137 backsolve(a, x, n, RE);
138 for (j = 0, xnorm = 0.0; j < n; j++) xnorm += fabs(x[j]);
139 if (xnorm > 0) est = est / xnorm;
144 ;;;;
145 ;;;; Make Rotation Matrix
146 ;;;;
148 (cffi:defcfun ("ccl_make_rotation_front" ccl-make-rotation-front)
149 :int (x size-t) (y :pointer) (z :pointer) (u :pointer) (v :int) (w :double))
150 (defun make-rotation-front (x y z u v w)
151 (ccl-make-rotation-front x y z u v (float w 1d0)))
153 ;;;;
154 ;;;; Eigenvalues and Eigenvectors
155 ;;;;
157 (cffi:defcfun ("ccl_eigen_front" ccl-eigen-front)
158 :int (x :pointer) (y size-t) (z :pointer) (u :pointer) (v :pointer))
159 (defun eigen-front (x y z u v)
160 (ccl-eigen-front x y z u v))
162 ;;;;
163 ;;;; Spline Interpolation
164 ;;;;
166 (cffi:defcfun ("ccl_range_to_rseq" ccl-range-to-rseq)
167 :int (x size-t) (y :pointer) (z size-t) (u :pointer))
168 (defun la-range-to-rseq (x y z u)
169 (ccl-range-to-rseq x y z u))
171 (cffi:defcfun ("ccl_spline_front" ccl-spline-front)
172 :int (x size-t) (y :pointer) (z :pointer) (u size-t) (v :pointer) (w :pointer) (a :pointer))
173 (defun spline-front (x y z u v w a)
174 (ccl-spline-front x y z u v w a))
176 ;;;;
177 ;;;; Kernel Density Estimators and Smoothers
178 ;;;;
180 (cffi:defcfun ("ccl_kernel_dens_front" ccl-kernel-dens-front)
181 :int (x :pointer) (y size-t) (z :double) (u :pointer) (v :pointer) (w size-t) (a :int))
182 (defun kernel-dens-front (x y z u v w a)
183 (ccl-kernel-dens-front x y (float z 1d0) u v w a))
185 (cffi:defcfun ("ccl_kernel_smooth_front" ccl-kernel-smooth-front)
186 :int (x :pointer) (y :pointer) (z size-t) (u :double) (v :pointer) (w :pointer) (a size-t) (b :int))
187 (defun kernel-smooth-front (x y z u v w a b)
188 (ccl-kernel-smooth-front x y z (float u 1d0) v w a b))
190 ;;;;
191 ;;;; Lowess Smoother Interface
192 ;;;;
194 (cffi:defcfun ("ccl_base_lowess_front" ccl-base-lowess-front)
195 :int (x :pointer) (y :pointer) (z size-t) (u :double) (v size-t) (w :double) (a :pointer) (b :pointer) (c :pointer))
196 (defun base-lowess-front (x y z u v w a b c)
197 (ccl-base-lowess-front x y z (float u 1d0) v (float w 1d0) a b c))
199 ;;;;
200 ;;;; FFT
201 ;;;;
203 (cffi:defcfun ("ccl_fft_front" ccl-fft-front)
204 :int (x size-t) (y :pointer) (z :pointer) (u :int))
205 (defun fft-front (x y z u)
206 (ccl-fft-front x y z u))
211 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
212 ;;;;
213 ;;;; Lisp to C number conversion and checking
214 ;;;;
215 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
217 ;;;;
218 ;;;; Lisp to/from C sequence and matrix conversion and checking
219 ;;;;
221 (defun is-cons (a)
222 "FIXME:AJR this is not used anywhere?"
223 (if (consp a) 1 0))
225 (defun check-fixnum (a)
226 (if (/= 0 (la-data-mode a)) (error "not an integer sequence - ~s" a)))
228 (defun check-real (data)
229 (let ((data (compound-data-seq data)))
230 (cond
231 ((vectorp data)
232 (let ((n (length data)))
233 (declare (fixnum n))
234 (dotimes (i n)
235 (declare (fixnum i))
236 (check-one-real (aref data i)))))
237 ((consp data) (dolist (x data) (check-one-real x)))
238 (t (error "bad sequence - ~s" data)))))
240 (defun vec-assign (a i x) (setf (aref a i) x))
242 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
243 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
244 ;;;;
245 ;;;; Lisp Interfaces to Linear Algebra Routines
246 ;;;;
247 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
248 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
250 ;;; FIXME: use dpbt[f2|rf], dpbstf, dpot[f2|rf]; dpptrf, zpbstf, zpbt[f2|rf]
251 ;;; remember: factorization = decomposition, depending on training.
253 (defun chol-decomp (a &optional (maxoffl 0.0))
254 "Args: (a)
255 Modified Cholesky decomposition. A should be a square, symmetric matrix.
256 Computes lower triangular matrix L such that L L^T = A + D where D is a
257 diagonal matrix. If A is strictly positive definite D will be zero.
258 Otherwise, D is as small as possible to make A + D numerically strictly
259 positive definite. Returns a list (L (max D))."
260 (check-square-matrix a)
261 (check-real a)
262 (let* ((n (array-dimension a 0))
263 (result (make-array (list n n)))
264 (dpars (list maxoffl 0.0)))
265 (check-real dpars)
266 (let ((mat (la-data-to-matrix a +mode-re+))
267 (dp (la-data-to-vector dpars +mode-re+)))
268 (unwind-protect
269 (progn
270 (chol-decomp-front mat n dp)
271 (la-matrix-to-data mat n n +mode-re+ result)
272 (la-vector-to-data dp 2 +mode-re+ dpars))
273 (la-free-matrix mat n)
274 (la-free-vector dp)))
275 (list result (second dpars))))
278 ;;; REPLACE with
279 ;;; (matlisp:lu M)
280 ;;; i.e. result use by:
281 ;;; (setf (values (lu-out1 lu-out2 lu-out3)) (matlisp:lu my-matrix))
282 ;;; for solution, ...
283 ;;; for lu-solve:
284 ;;; (matlisp:gesv a b &opt ipivot)
286 (defun lu-decomp (a)
287 "Args: (a)
288 A is a square matrix of numbers (real or complex). Computes the LU
289 decomposition of A and returns a list of the form (LU IV D FLAG), where
290 LU is a matrix with the L part in the lower triangle, the U part in the
291 upper triangle (the diagonal entries of L are taken to be 1), IV is a vector
292 describing the row permutation used, D is 1 if the number of permutations
293 is odd, -1 if even, and FLAG is T if A is numerically singular, NIL otherwise.
294 Used bu LU-SOLVE."
295 (check-square-matrix a)
296 (let* ((n (array-dimension a 0))
297 (mode (max +mode-re+ (la-data-mode a)))
298 (result (list (make-array (list n n)) (make-array n) nil nil)))
299 (let ((mat (la-data-to-matrix a mode))
300 (iv (la-vector n +mode-in+))
301 (d (la-vector 1 +mode-re+))
302 (singular 0))
303 (unwind-protect
304 (progn
305 (setf singular (lu-decomp-front mat n iv mode d))
306 (la-matrix-to-data mat n n mode (first result))
307 (la-vector-to-data iv n +mode-in+ (second result))
308 (setf (third result) (la-get-double d 0))
309 (setf (fourth result) (if (= singular 0.0) nil t)))
310 (la-free-matrix mat n)
311 (la-free-vector iv)
312 (la-free-vector d)))
313 result))
315 (defun lu-solve (lu lb)
316 "Args: (lu b)
317 LU is the result of (LU-DECOMP A) for a square matrix A, B is a sequence.
318 Returns the solution to the equation Ax = B. Signals an error if A is
319 singular."
320 (let ((la (first lu))
321 (lidx (second lu)))
322 (check-square-matrix la)
323 (check-sequence lidx)
324 (check-sequence lb)
325 (check-fixnum lidx)
326 (let* ((n (num-rows la))
327 (result (make-sequence (if (consp lb) 'list 'vector) n))
328 (a-mode (la-data-mode la))
329 (b-mode (la-data-mode lb)))
330 (if (/= n (length lidx)) (error "index sequence is wrong length"))
331 (if (/= n (length lb)) (error "right hand side is wrong length"))
332 (let* ((mode (max +mode-re+ a-mode b-mode))
333 (a (la-data-to-matrix la mode))
334 (indx (la-data-to-vector lidx +mode-in+))
335 (b (la-data-to-vector lb mode))
336 (singular 0))
337 (unwind-protect
338 (progn
339 (setf singular (lu-solve-front a n indx b mode))
340 (la-vector-to-data b n mode result))
341 (la-free-matrix a n)
342 (la-free-vector indx)
343 (la-free-vector b))
344 (if (/= 0.0 singular) (error "matrix is (numerically) singular"))
345 result))))
347 (defun determinant (a)
348 "Args: (m)
349 Returns the determinant of the square matrix M."
350 (let* ((lu (lu-decomp a))
351 (la (first lu))
352 (n (num-rows a))
353 (d1 (third lu))
354 (d2 0.d0))
355 (declare (fixnum n))
356 (flet ((fabs (x) (float (abs x) 0.d0)))
357 (dotimes (i n (* d1 (exp d2)))
358 (declare (fixnum i))
359 (let* ((x (aref la i i))
360 (magn (fabs x)))
361 (if (= 0.0 magn) (return 0.d0))
362 (setf d1 (* d1 (/ x magn)))
363 (setf d2 (+ d2 (log magn))))))))
365 (defun inverse (a)
366 "Args: (m)
367 Returns the inverse of the the square matrix M; signals an error if M is ill
368 conditioned or singular"
369 (check-square-matrix a)
370 (let ((n (num-rows a))
371 (mode (max +mode-re+ (la-data-mode a))))
372 (declare (fixnum n))
373 (let ((result (make-array (list n n) :initial-element 0)))
374 (dotimes (i n)
375 (declare (fixnum i))
376 (setf (aref result i i) 1))
377 (let ((mat (la-data-to-matrix a mode))
378 (inv (la-data-to-matrix result mode))
379 (iv (la-vector n +mode-in+))
380 (v (la-vector n mode))
381 (singular 0))
382 (unwind-protect
383 (progn
384 (setf singular (lu-inverse-front mat n iv v mode inv))
385 (la-matrix-to-data inv n n mode result))
386 (la-free-matrix mat n)
387 (la-free-matrix inv n)
388 (la-free-vector iv)
389 (la-free-vector v))
390 (if (/= singular 0) (error "matrix is (numerically) singular"))
391 result))))
393 ;;;;
394 ;;;; SV Decomposition
395 ;;;;
397 (defun sv-decomp (a)
398 "Args: (a)
399 A is a matrix of real numbers with at least as many rows as columns.
400 Computes the singular value decomposition of A and returns a list of the form
401 (U W V FLAG) where U and V are matrices whose columns are the left and right
402 singular vectors of A and W is the sequence of singular values of A. FLAG is T
403 if the algorithm converged, NIL otherwise."
404 (check-matrix a)
405 (let* ((m (num-rows a))
406 (n (num-cols a))
407 (mode (max +mode-re+ (la-data-mode a)))
408 (result (list (make-array (list m n))
409 (make-array n)
410 (make-array (list n n))
411 nil)))
412 (if (< m n) (error "number of rows less than number of columns"))
413 (if (= mode +mode-cx+) (error "complex SVD not available yet"))
414 (let ((mat (la-data-to-matrix a mode))
415 (w (la-vector n +mode-re+))
416 (v (la-matrix n n +mode-re+))
417 (converged 0))
418 (unwind-protect
419 (progn
420 (setf converged (sv-decomp-front mat m n w v))
421 (la-matrix-to-data mat m n mode (first result))
422 (la-vector-to-data w n mode (second result))
423 (la-matrix-to-data v n n mode (third result))
424 (setf (fourth result) (if (/= 0.0 converged) t nil)))
425 (la-free-matrix mat m)
426 (la-free-vector w)
427 (la-free-matrix v n))
428 result)))
431 ;;;;
432 ;;;; QR Decomposition
433 ;;;;
435 (defun qr-decomp (a &optional pivot)
436 "Args: (a &optional pivot)
437 A is a matrix of real numbers with at least as many rows as columns. Computes
438 the QR factorization of A and returns the result in a list of the form (Q R).
439 If PIVOT is true the columns of X are first permuted to place insure the
440 absolute values of the diagonal elements of R are nonincreasing. In this case
441 the result includes a third element, a list of the indices of the columns in
442 the order in which they were used."
443 (check-matrix a)
444 (let* ((m (num-rows a))
445 (n (num-cols a))
446 (mode (max +mode-re+ (la-data-mode a)))
447 (p (if pivot 1 0))
448 (result (if pivot
449 (list (make-array (list m n))
450 (make-array (list n n))
451 (make-array n))
452 (list (make-array (list m n)) (make-array (list n n))))))
453 (if (< m n) (error "number of rows less than number of columns"))
454 (if (= mode +mode-cx+) (error "complex QR decomposition not available yet"))
455 (let ((mat (la-data-to-matrix a mode))
456 (v (la-matrix n n +mode-re+))
457 (jpvt (la-vector n +mode-in+)))
458 (unwind-protect
459 (progn
460 (qr-decomp-front mat m n v jpvt p)
461 (la-matrix-to-data mat m n mode (first result))
462 (la-matrix-to-data v n n mode (second result))
463 (if pivot (la-vector-to-data jpvt n +mode-in+ (third result))))
464 (la-free-matrix mat m)
465 (la-free-matrix v n)
466 (la-free-vector jpvt))
467 result)))
469 ;;;;
470 ;;;; Estimate of Condition Number for Lower Triangular Matrix
471 ;;;;
473 (defun rcondest (a)
474 "Args: (a)
475 Returns an estimate of the reciprocal of the L1 condition number of an upper
476 triangular matrix a."
477 (check-square-matrix a)
478 (let ((mode (max +mode-re+ (la-data-mode a)))
479 (n (num-rows a)))
480 (if (= mode +mode-cx+)
481 (error "complex condition estimate not available yet"))
482 (let ((mat (la-data-to-matrix a mode))
483 (est 0.0))
484 (unwind-protect
485 (setf est (rcondest-front mat n))
486 (la-free-matrix mat n))
487 est)))
489 ;;;;
490 ;;;; Make Rotation Matrix
491 ;;;;
493 (defun make-rotation (x y &optional alpha)
494 "Args: (x y &optional alpha)
495 Returns a rotation matrix for rotating from X to Y, or from X toward Y
496 by angle ALPHA, in radians. X and Y are sequences of the same length."
497 (check-sequence x)
498 (check-sequence y)
499 (if alpha (check-one-real alpha))
500 (let* ((n (length x))
501 (mode (max +mode-re+ (la-data-mode x) (la-data-mode y)))
502 (use-angle (if alpha 1 0))
503 (angle (if alpha (float alpha 0.0) 0.0))
504 (result (make-array (list n n))))
505 (if (/= n (length y)) (error "sequences not the same length"))
506 (if (= mode +mode-cx+) (error "complex data not supported yet"))
507 (let ((px (la-data-to-vector x +mode-re+))
508 (py (la-data-to-vector y +mode-re+))
509 (rot (la-matrix n n +mode-re+)))
510 (unwind-protect
511 (progn
512 (make-rotation-front n rot px py use-angle angle)
513 (la-matrix-to-data rot n n +mode-re+ result))
514 (la-free-vector px)
515 (la-free-vector py)
516 (la-free-matrix rot n))
517 result)))
519 ;;;;
520 ;;;; Eigenvalues and Vectors
521 ;;;;
523 (defun eigen (a)
524 "Args: (a)
525 Returns list of list of eigenvalues and list of eigenvectors of square,
526 symmetric matrix A. Third element of result is NIL if algorithm converges.
527 If the algorithm does not converge, the third element is an integer I.
528 In this case the eigenvalues 0, ..., I are not reliable."
529 (check-square-matrix a)
530 (let ((mode (max +mode-re+ (la-data-mode a)))
531 (n (num-rows a)))
532 (if (= mode +mode-cx+) (error "matrix must be real and symmetric"))
533 (let ((evals (make-array n))
534 (evecs (make-list (* n n)))
535 (pa (la-data-to-vector (compound-data-seq a) +mode-re+))
536 (w (la-vector n +mode-re+))
537 (z (la-vector (* n n) +mode-re+))
538 (fv1 (la-vector n +mode-re+))
539 (ierr 0))
540 (unwind-protect
541 (progn
542 (setf ierr (eigen-front pa n w z fv1))
543 (la-vector-to-data w n +mode-re+ evals)
544 (la-vector-to-data z (* n n) +mode-re+ evecs))
545 (la-free-vector pa)
546 (la-free-vector z)
547 (la-free-vector w)
548 (la-free-vector fv1))
549 (list (nreverse evals)
550 (nreverse (mapcar #'(lambda (x) (coerce x 'vector))
551 (split-list evecs n)))
552 (if (/= 0 ierr) (- n ierr))))))
554 ;;;;
555 ;;;; Spline Interpolation
556 ;;;;
558 (defun make-smoother-args (x y xvals)
559 (check-sequence x)
560 (check-real x)
561 (when y
562 (check-sequence y)
563 (check-real y))
564 (unless (integerp xvals)
565 (check-sequence xvals)
566 (check-real xvals))
567 (let* ((n (length x))
568 (ns (if (integerp xvals) xvals (length xvals)))
569 (result (list (make-list ns) (make-list ns))))
570 (if (and y (/= n (length y))) (error "sequences not the same length"))
571 (list x y n (if (integerp xvals) 0 1) ns xvals result)))
573 (defun get-smoother-result (args) (seventh args))
575 (defmacro with-smoother-data ((x y xvals is-reg) &rest body)
576 `(progn
577 (check-sequence ,x)
578 (check-real ,x)
579 (when ,is-reg
580 (check-sequence ,y)
581 (check-real ,y))
582 (unless (integerp ,xvals)
583 (check-sequence ,xvals)
584 (check-real ,xvals))
585 (let* ((supplied (not (integerp ,xvals)))
586 (n (length ,x))
587 (ns (if supplied (length ,xvals) ,xvals))
588 (result (list (make-list ns) (make-list ns))))
589 (if (and ,is-reg (/= n (length ,y)))
590 (error "sequences not the same length"))
591 (if (and (not supplied) (< ns 2))
592 (error "too few points for interpolation"))
593 (let* ((px (la-data-to-vector ,x +mode-re+))
594 (py (if ,is-reg (la-data-to-vector ,y +mode-re+)))
595 (pxs (if supplied
596 (la-data-to-vector ,xvals +mode-re+)
597 (la-vector ns +mode-re+)))
598 (pys (la-vector ns +mode-re+)))
599 (unless supplied (la-range-to-rseq n px ns pxs))
600 (unwind-protect
601 (progn ,@body
602 (la-vector-to-data pxs ns +mode-re+ (first result))
603 (la-vector-to-data pys ns +mode-re+ (second result)))
604 (la-free-vector px)
605 (if ,is-reg (la-free-vector py))
606 (la-free-vector pxs)
607 (la-free-vector pys))
608 result))))
610 (defun spline (x y &key (xvals 30))
611 "Args: (x y &key xvals)
612 Returns list of x and y values of natural cubic spline interpolation of (X,Y).
613 X must be strictly increasing. XVALS can be an integer, the number of equally
614 spaced points to use in the range of X, or it can be a sequence of points at
615 which to interpolate."
616 (with-smoother-data (x y xvals t)
617 (let ((work (la-vector (* 2 n) +mode-re+))
618 (error 0))
619 (unwind-protect
620 (setf error (spline-front n px py ns pxs pys work))
621 (la-free-vector work))
622 (if (/= error 0) (error "bad data for splines")))))
624 ;;;;
625 ;;;; Kernel Density Estimators and Smoothers
626 ;;;;
628 (defun kernel-type-code (type)
629 (cond ((eq type 'u) 0)
630 ((eq type 't) 1)
631 ((eq type 'g) 2)
632 (t 3)))
634 (defun kernel-dens (x &key (type 'b) (width -1.0) (xvals 30))
635 "Args: (x &key xvals width type)
636 Returns list of x and y values of kernel density estimate of X. XVALS can be an
637 integer, the number of equally spaced points to use in the range of X, or it
638 can be a sequence of points at which to interpolate. WIDTH specifies the
639 window width. TYPE specifies the lernel and should be one of the symbols G, T,
640 U or B for gaussian, triangular, uniform or bisquare. The default is B."
641 (check-one-real width)
642 (with-smoother-data (x nil xvals nil) ;; warning about deleting unreachable code is TRUE -- 2nd arg=nil!
643 (let ((code (kernel-type-code type))
644 (error 0))
645 (setf error (kernel-dens-front px n width pxs pys ns code))
646 (if (/= 0 error) (error "bad kernel density data")))))
648 (defun kernel-smooth (x y &key (type 'b) (width -1.0) (xvals 30))
649 "Args: (x y &key xvals width type)
650 Returns list of x and y values of kernel smooth of (X,Y). XVALS can be an
651 integer, the number of equally spaced points to use in the range of X, or it
652 can be a sequence of points at which to interpolate. WIDTH specifies the
653 window width. TYPE specifies the lernel and should be one of the symbols G, T,
654 U or B for Gaussian, triangular, uniform or bisquare. The default is B."
655 (check-one-real width)
656 (with-smoother-data (x y xvals t)
657 (let ((code (kernel-type-code type))
658 (error 0))
659 (kernel-smooth-front px py n width pxs pys ns code)
660 ;; if we get the Lisp version ported from C, uncomment below and
661 ;; comment above. (thanks to Carlos Ungil for the initial CFFI
662 ;; work).
663 ;;(kernel-smooth-Cport px py n width pxs pys ns code)
664 (if (/= 0 error) (error "bad kernel density data")))))
668 (defun kernel-smooth-Cport (px py n width ;;wts wds ;; see above for mismatch?
669 xs ys ns ktype)
670 "Port of kernel_smooth (Lib/kernel.c) to Lisp.
671 FIXME:kernel-smooth-Cport : This is broken.
672 Until this is fixed, we are using Luke's C code and CFFI as glue."
673 (declare (ignore width xs))
674 (cond ((< n 1) 1.0)
675 ((and (< n 2) (<= width 0)) 1.0)
676 (t (let* ((xmin (min px))
677 (xmax (max px))
678 (width (/ (- xmax xmin) (+ 1.0 (log n)))))
679 (dotimes (i (- ns 1))
680 (setf (aref ys i)
681 (let ((wsum 0.0)
682 (ysum 0.0))
683 (dotimes (j (- n 1)) )
684 ;;;possible nasty errors...
685 ;; (let*
686 ;; ((lwidth (if wds (* width (aref wds j)) width))
687 ;; (lwt (* (kernel-Cport (aref xs i) (aref px j) lwidth ktype) ;; px?
688 ;; (if wts (aref wts j) 1.0))))
689 ;; (setf wsum (+ wsum lwt))
690 ;; (setf ysum (if py (+ ysum (* lwt (aref py j)))))) ;; py? y?
692 ;;; end of errors
693 (if py
694 (if (> wsum 0.0)
695 (/ ysum wsum)
696 0.0)
697 (/ wsum n)))))
698 (values ys)))))
702 (defun kernel-Cport (x y w ktype)
703 "Port of kernel() (Lib/kernel.c) to Lisp.
704 x,y,w are doubles, type is an integer"
705 (if (<= w 0.0)
707 (let ((z (- x y)))
708 (cond ((eq ktype "B")
709 (let* ((w (* w 2.0))
710 (z (* z 0.5)))
711 (if (and (> z -0.5)
712 (< z 0.5))
713 (/ (/ (* 15.0 (* (- 1.0 (* 4 z z)) ;; k/w
714 (- 1.0 (* 4 z z)))) ;; k/w
715 8.0)
717 0)))
718 ((eq ktype "G")
719 (let* ((w (* w 0.25))
720 (z (* z 4.0))
721 (k (/ (exp (* -0.5 z z))
722 (sqrt (* 2 PI)))))
723 (/ k w)))
724 ((eq ktype "U")
725 (let* ((w (* 1.5 w))
726 (z (* z 0.75))
727 (k (if (< (abs z) 0.5)
729 0.0)))
730 (/ k w)))
731 ((eq ktype "T")
732 (cond ((and (> z -1.0)
733 (< z 0.0))
734 (+ 1.0 z)) ;; k
735 ((and (> z 0.0)
736 (< z 1.0))
737 (- 1.0 z)) ;; k
738 (t 0.0)))
739 (t (values 0.0))))))
742 ;;;;
743 ;;;; Lowess Smoother Interface
744 ;;;;
746 (defun |base-lowess| (s1 s2 f nsteps delta)
747 (check-sequence s1)
748 (check-sequence s2)
749 (check-real s1)
750 (check-real s2)
751 (check-one-real f)
752 (check-one-fixnum nsteps)
753 (check-one-real delta)
754 (let* ((n (length s1))
755 (result (make-list n)))
756 (if (/= n (length s2)) (error "sequences not the same length"))
757 (let ((x (la-data-to-vector s1 +mode-re+))
758 (y (la-data-to-vector s2 +mode-re+))
759 (ys (la-vector n +mode-re+))
760 (rw (la-vector n +mode-re+))
761 (res (la-vector n +mode-re+))
762 (error 0))
763 (unwind-protect
764 (progn
765 (setf error (base-lowess-front x y n f nsteps delta ys rw res))
766 (la-vector-to-data ys n +mode-re+ result))
767 (la-free-vector x)
768 (la-free-vector y)
769 (la-free-vector ys)
770 (la-free-vector rw)
771 (la-free-vector res))
772 (if (/= error 0) (error "bad data for lowess"))
773 result)))
776 static LVAL add_contour_point(i, j, k, l, x, y, z, v, result)
777 int i, j, k, l;
778 RVector x, y;
779 RMatrix z;
780 double v;
781 LVAL result;
783 LVAL pt;
784 double p, q;
786 if ((z[i][j] <= v && v < z[k][l]) || (z[k][l] <= v && v < z[i][j])) {
787 xlsave(pt);
788 pt = mklist(2, NIL);
789 p = (v - z[i][j]) / (z[k][l] - z[i][j]);
790 q = 1.0 - p;
791 rplaca(pt, cvflonum((FLOTYPE) (q * x[i] + p * x[k])));
792 rplaca(cdr(pt), cvflonum((FLOTYPE) (q * y[j] + p * y[l])));
793 result = cons(pt, result);
794 xlpop();
796 return(result);
799 LVAL xssurface_contour()
801 LVAL s1, s2, mat, result;
802 RVector x, y;
803 RMatrix z;
804 double v;
805 int i, j, n, m;
807 s1 = xsgetsequence();
808 s2 = xsgetsequence();
809 mat = xsgetmatrix();
810 v = makedouble(xlgetarg());
811 xllastarg();
813 n = seqlen(s1); m = seqlen(s2);
814 if (n != numrows(mat) || m != numcols(mat)) xlfail("dimensions do not match");
815 if (data_mode(s1) == CX || data_mode(s2) == CX || data_mode(mat) == CX)
816 xlfail("data must be real");
818 x = (RVector) data_to_vector(s1, RE);
819 y = (RVector) data_to_vector(s2, RE);
820 z = (RMatrix) data_to_matrix(mat, RE);
822 xlsave1(result);
823 result = NIL;
824 for (i = 0; i < n - 1; i++) {
825 for (j = 0; j < m - 1; j++) {
826 result = add_contour_point(i, j, i, j+1, x, y, z, v, result);
827 result = add_contour_point(i, j+1, i+1, j+1, x, y, z, v, result);
828 result = add_contour_point(i+1, j+1, i+1, j, x, y, z, v, result);
829 result = add_contour_point(i+1, j, i, j, x, y, z, v, result);
832 xlpop();
834 free_vector(x);
835 free_vector(y);
836 free_matrix(z, n);
838 return(result);
843 ;;; FFT
845 ;;; FIXME:ajr
846 ;;; ??replace with matlisp:fft and matlisp:ifft (the latter for inverse mapping)
848 (defun fft (x &optional inverse)
849 "Args: (x &optional inverse)
850 Returns unnormalized Fourier transform of X, or inverse transform if INVERSE
851 is true."
852 (check-sequence x)
853 (let* ((n (length x))
854 ;;(mode (la-data-mode x))
855 (isign (if inverse -1 1))
856 (result (if (consp x) (make-list n) (make-array n))))
857 (let ((px (la-data-to-vector x +mode-cx+))
858 (work (la-vector (+ (* 4 n) 15) +mode-re+)))
859 (unwind-protect
860 (progn
861 (fft-front n px work isign)
862 (la-vector-to-data px n +mode-cx+ result))
863 (la-free-vector px)
864 (la-free-vector work))
865 result)))
868 ;;; SWEEP Operator: FIXME: use matlisp
871 (defun make-sweep-front (x y w n p mode has_w x_mean result)
872 (declare (fixnum n p mode has_w))
873 (let ((x_data nil)
874 (result_data nil)
875 (val 0.0)
876 (dxi 0.0)
877 (dyi 0.0)
878 (dv 0.0)
879 (dw 0.0)
880 (sum_w 0.0)
881 (dxik 0.0)
882 (dxjk 0.0)
883 (dyj 0.0)
884 (dx_meani 0.0)
885 (dx_meanj 0.0)
886 (dy_mean 0.0)
887 (has-w (if (/= 0 has_w) t nil))
888 (RE 1))
889 (declare (long-float val dxi dyi dv dw sum_w dxik dxjk dyj
890 dx_meani dx_meanj dy_mean)) ;; originally "declare-double" macro
892 (if (> mode RE) (error "not supported for complex data yet"))
894 (setf x_data (compound-data-seq x))
895 (setf result_data (compound-data-seq result))
897 ;; find the mean of y
898 (setf val 0.0)
899 (setf sum_w 0.0)
900 (dotimes (i n)
901 (declare (fixnum i))
902 (setf dyi (makedouble (aref y i)))
903 (when has-w
904 (setf dw (makedouble (aref w i)))
905 (incf sum_w dw)
906 (setf dyi (* dyi dw)))
907 (incf val dyi))
908 (if (not has-w) (setf sum_w (float n 0.0)))
909 (if (<= sum_w 0.0) (error "non positive sum of weights"))
910 (setf dy_mean (/ val sum_w))
912 ;; find the column means
913 (dotimes (j p)
914 (declare (fixnum j))
915 (setf val 0.0)
916 (dotimes (i n)
917 (declare (fixnum i))
918 (setf dxi (makedouble (aref x_data (+ (* p i) j))))
919 (when has-w
920 (setf dw (makedouble (aref w i)))
921 (setf dxi (* dxi dw)))
922 (incf val dxi))
923 (setf (aref x_mean j) (/ val sum_w)))
925 ;; put 1/sum_w in topleft, means on left, minus means on top
926 (setf (aref result_data 0) (/ 1.0 sum_w))
927 (dotimes (i p)
928 (declare (fixnum i))
929 (setf dxi (makedouble (aref x_mean i)))
930 (setf (aref result_data (+ i 1)) (- dxi))
931 (setf (aref result_data (* (+ i 1) (+ p 2))) dxi))
932 (setf (aref result_data (+ p 1)) (- dy_mean))
933 (setf (aref result_data (* (+ p 1) (+ p 2))) dy_mean)
935 ;; put sums of adjusted cross products in body
936 (dotimes (i p)
937 (declare (fixnum i))
938 (dotimes (j p)
939 (declare (fixnum j))
940 (setf val 0.0)
941 (dotimes (k n)
942 (declare (fixnum k))
943 (setf dxik (makedouble (aref x_data (+ (* p k) i))))
944 (setf dxjk (makedouble (aref x_data (+ (* p k) j))))
945 (setf dx_meani (makedouble (aref x_mean i)))
946 (setf dx_meanj (makedouble (aref x_mean j)))
947 (setf dv (* (- dxik dx_meani) (- dxjk dx_meanj)))
948 (when has-w
949 (setf dw (makedouble (aref w k)))
950 (setf dv (* dv dw)))
951 (incf val dv))
952 (setf (aref result_data (+ (* (+ i 1) (+ p 2)) (+ j 1))) val)
953 (setf (aref result_data (+ (* (+ j 1) (+ p 2)) (+ i 1))) val))
954 (setf val 0.0)
955 (dotimes (j n)
956 (declare (fixnum j))
957 (setf dxik (makedouble (aref x_data (+ (* p j) i))))
958 (setf dyj (makedouble (aref y j)))
959 (setf dx_meani (makedouble (aref x_mean i)))
960 (setf dv (* (- dxik dx_meani) (- dyj dy_mean)))
961 (when has-w
962 (setf dw (makedouble (aref w j)))
963 (setf dv (* dv dw)))
964 (incf val dv))
965 (setf (aref result_data (+ (* (+ i 1) (+ p 2)) (+ p 1))) val)
966 (setf (aref result_data (+ (* (+ p 1) (+ p 2)) (+ i 1))) val))
967 (setf val 0.0)
968 (dotimes (j n)
969 (declare (fixnum j))
970 (setf dyj (makedouble (aref y j)))
971 (setf dv (* (- dyj dy_mean) (- dyj dy_mean)))
972 (when has-w
973 (setf dw (makedouble (aref w j)))
974 (setf dv (* dv dw)))
975 (incf val dv))
976 (setf (aref result_data (+ (* (+ p 1) (+ p 2)) (+ p 1))) val)))
978 ;;; FIXME: use matlisp
979 (defun sweep-in-place-front (a rows cols mode k tol)
980 "Sweep algorithm for linear regression."
981 (declare (long-float tol))
982 (declare (fixnum rows cols mode k))
983 (let ((data nil)
984 (pivot 0.0)
985 (aij 0.0)
986 (aik 0.0)
987 (akj 0.0)
988 (akk 0.0)
989 (RE 1))
990 (declare (long-float pivot aij aik akj akk))
992 (if (> mode RE) (error "not supported for complex data yet"))
993 (if (or (< k 0) (>= k rows) (>= k cols)) (error "index out of range"))
995 (setf tol (max tol machine-epsilon))
996 (setf data (compound-data-seq a))
998 (setf pivot (makedouble (aref data (+ (* cols k) k))))
1000 (cond
1001 ((or (> pivot tol) (< pivot (- tol)))
1002 (dotimes (i rows)
1003 (declare (fixnum i))
1004 (dotimes (j cols)
1005 (declare (fixnum j))
1006 (when (and (/= i k) (/= j k))
1007 (setf aij (makedouble (aref data (+ (* cols i) j))))
1008 (setf aik (makedouble (aref data (+ (* cols i) k))))
1009 (setf akj (makedouble (aref data (+ (* cols k) j))))
1010 (setf aij (- aij (/ (* aik akj) pivot)))
1011 (setf (aref data (+ (* cols i) j)) aij))))
1013 (dotimes (i rows)
1014 (declare (fixnum i))
1015 (setf aik (makedouble (aref data (+ (* cols i) k))))
1016 (when (/= i k)
1017 (setf aik (/ aik pivot))
1018 (setf (aref data (+ (* cols i) k)) aik)))
1020 (dotimes (j cols)
1021 (declare (fixnum j))
1022 (setf akj (makedouble (aref data (+ (* cols k) j))))
1023 (when (/= j k)
1024 (setf akj (- (/ akj pivot)))
1025 (setf (aref data (+ (* cols k) j)) akj)))
1027 (setf akk (/ 1.0 pivot))
1028 (setf (aref data (+ (* cols k) k)) akk)
1030 (t 0))))
1032 ;; FIXME: use matlisp
1033 (defun make-sweep-matrix (x y &optional w)
1034 "Args: (x y &optional weights)
1035 X is matrix, Y and WEIGHTS are sequences. Returns the sweep matrix of the
1036 (weighted) regression of Y on X"
1037 (check-matrix x)
1038 (check-sequence y)
1039 (if w (check-sequence w))
1040 (let ((n (num-rows x))
1041 (p (num-cols x)))
1042 (if (/= n (length y)) (error "dimensions do not match"))
1043 (if (and w (/= n (length w))) (error "dimensions do not match"))
1044 (let ((mode (max (la-data-mode x)
1045 (la-data-mode x)
1046 (if w (la-data-mode w) 0)))
1047 (result (make-array (list (+ p 2) (+ p 2))))
1048 (x-mean (make-array p))
1049 (y (coerce y 'vector))
1050 (w (if w (coerce w 'vector)))
1051 (has-w (if w 1 0)))
1052 (make-sweep-front x y w n p mode has-w x-mean result)
1053 result)))
1055 (defun sweep-in-place (a k tol)
1056 (check-matrix a)
1057 (check-one-fixnum k)
1058 (check-one-real tol)
1059 (let ((rows (num-rows a))
1060 (cols (num-cols a))
1061 (mode (la-data-mode a)))
1062 (let ((swept (sweep-in-place-front a rows cols mode k tol)))
1063 (if (/= 0 swept) t nil))))
1065 (defun sweep-operator (a columns &optional tolerances)
1066 "Args: (a indices &optional tolerances)
1068 A is a matrix, INDICES a sequence of the column indices to be
1069 swept. Returns a list of the swept result and the list of the columns
1070 actually swept. (See MULTREG documentation.) If supplied, TOLERANCES
1071 should be a list of real numbers the same length as INDICES. An index
1072 will only be swept if its pivot element is larger than the
1073 corresponding element of TOLERANCES."
1075 (check-matrix a)
1076 (if (not (typep columns 'sequence))
1077 (setf columns (list columns)))
1078 (check-sequence columns)
1079 (if tolerances
1080 (progn
1081 (if (not (typep tolerances 'sequence))
1082 (setf tolerances (list tolerances)))
1083 (check-sequence tolerances)))
1085 (check-real a)
1086 (check-fixnum columns)
1087 (if tolerances (check-real tolerances))
1088 (do ((tol .0000001)
1089 (result (copy-array a))
1090 (swept-columns nil)
1091 (columns (coerce columns 'list) (cdr columns))
1092 (tolerances (if (consp tolerances) (coerce tolerances 'list))
1093 (if (consp tolerances) (cdr tolerances))))
1094 ((null columns) (list result swept-columns))
1095 (let ((col (first columns))
1096 (tol (if (consp tolerances) (first tolerances) tol)))
1097 (if (sweep-in-place result col tol)
1098 (setf swept-columns (cons col swept-columns))))))
1102 ;;; AX+Y
1105 ;;; matlisp:axpy
1107 (defun ax+y (a x y &optional lower)
1108 "Args (a x y &optional lower)
1109 Returns (+ (matmult A X) Y). If LOWER is not nil, A is taken to be lower
1110 triangular.
1111 This could probably be made more efficient."
1112 (check-square-matrix a)
1113 (check-sequence x)
1114 (check-sequence y)
1115 (check-real a)
1116 (check-real x)
1117 (check-real y)
1118 (let* ((n (num-rows a))
1119 (result (make-list n))
1120 (a (compound-data-seq a)))
1121 (declare (fixnum n))
1122 (if (or (/= n (length x)) (/= n (length y)))
1123 (error "dimensions do not match"))
1124 (do* ((tx (make-next-element x) (make-next-element x))
1125 (ty (make-next-element y))
1126 (tr (make-next-element result))
1127 (i 0 (+ i 1))
1128 (start 0 (+ start n))
1129 (end (if lower (+ i 1) n) (if lower (+ i 1) n)))
1130 ((<= n i) result)
1131 (declare (fixnum i start end))
1132 (let ((val (get-next-element ty i)))
1133 (dotimes (j end)
1134 (declare (fixnum j))
1135 (setf val (+ val (* (get-next-element tx j)
1136 (aref a (+ start j))))))
1137 (set-next-element tr i val)))))
1143 ;;;;
1144 ;;;; Linear Algebra Functions
1145 ;;;;
1147 (defun matrix (dim data)
1148 "Args: (dim data)
1149 returns a matrix of dimensions DIM initialized using sequence DATA
1150 in row major order."
1151 (let ((dim (coerce dim 'list))
1152 (data (coerce data 'list)))
1153 (make-array dim :initial-contents (split-list data (nth 1 dim)))))
1155 (defun flatsize (x)
1156 (length x)) ;; FIXME: defined badly!!
1158 (defun print-matrix (a &optional (stream *standard-output*))
1159 "Args: (matrix &optional stream)
1160 Prints MATRIX to STREAM in a nice form that is still machine readable"
1161 (unless (matrixp a) (error "not a matrix - ~a" a))
1162 (let ((size (min 15 (max (map-elements #'flatsize a)))))
1163 (format stream "#2a(~%")
1164 (dolist (x (row-list a))
1165 (format stream " (")
1166 (let ((n (length x)))
1167 (dotimes (i n)
1168 (let ((y (aref x i)))
1169 (cond
1170 ((integerp y) (format stream "~vd" size y))
1171 ((floatp y) (format stream "~vg" size y))
1172 (t (format stream "~va" size y))))
1173 (if (< i (- n 1)) (format stream " "))))
1174 (format stream ")~%"))
1175 (format stream " )~%")
1176 nil))
1178 (defun solve (a b)
1179 "Args: (a b)
1180 Solves A x = B using LU decomposition and backsolving. B can be a sequence
1181 or a matrix."
1182 (let ((lu (lu-decomp a)))
1183 (if (matrixp b)
1184 (apply #'bind-columns
1185 (mapcar #'(lambda (x) (lu-solve lu x)) (column-list b)))
1186 (lu-solve lu b))))
1188 (defun backsolve (a b)
1189 "Args: (a b)
1190 Solves A x = B by backsolving, assuming A is upper triangular. B must be a
1191 sequence. For use with qr-decomp."
1192 (let* ((n (length b))
1193 (sol (make-array n)))
1194 (dotimes (i n)
1195 (let* ((k (- n i 1))
1196 (val (elt b k)))
1197 (dotimes (j i)
1198 (let ((l (- n j 1)))
1199 (setq val (- val (* (aref sol l) (aref a k l))))))
1200 (setf (aref sol k) (/ val (aref a k k)))))
1201 (if (listp b) (coerce sol 'list) sol)))
1203 (defun eigenvalues (a)
1204 "Args: (a)
1205 Returns list of eigenvalues of square, symmetric matrix A"
1206 (first (eigen a)))
1208 (defun eigenvectors (a)
1209 "Args: (a)
1210 Returns list of eigenvectors of square, symmetric matrix A"
1211 (second (eigen a)))
1213 (defun accumulate (f s)
1214 "Args: (f s)
1215 Accumulates elements of sequence S using binary function F.
1216 (accumulate #'+ x) returns the cumulative sum of x."
1217 (let* ((result (list (elt s 0)))
1218 (tail result))
1219 (flet ((acc (dummy x)
1220 (rplacd tail (list (funcall f (first tail) x)))
1221 (setf tail (cdr tail))))
1222 (reduce #'acc s))
1223 (if (vectorp s) (coerce result 'vector) result)))
1225 (defun cumsum (x)
1226 "Args: (x)
1227 Returns the cumulative sum of X."
1228 (accumulate #'+ x))
1230 (defun combine (&rest args)
1231 "Args (&rest args)
1232 Returns sequence of elements of all arguments."
1233 (copy-seq (element-seq args)))
1235 (defun lowess (x y &key (f .25) (steps 2) (delta -1) sorted)
1236 "Args: (x y &key (f .25) (steps 2) delta sorted)
1237 Returns (list X YS) with YS the LOWESS fit. F is the fraction of data used for
1238 each point, STEPS is the number of robust iterations. Fits for points within
1239 DELTA of each other are interpolated linearly. If the X values setting SORTED
1240 to T speeds up the computation."
1241 (let ((x (if sorted x (sort-data x)))
1242 (y (if sorted y (select y (order x))))
1243 (delta (if (> delta 0.0) delta (/ (- (max x) (min x)) 50))))
1244 (list x y delta f steps)));; (|base-lowess| x y f steps delta))))