removed CLSR from master -- still in tonylocal, and need clr in tonylocal as well
[rclg.git] / old / rclg.lisp
blobae68cd933b9cbfd50d5a8725e62a48c9a6445cc5
1 ;;; Copyright rif 2004
3 (declaim (optimize (speed 3) (debug 0) (safety 1)))
4 ;; (declaim (optimize (speed 1) (safety 3) (debug 3)))
6 (defpackage "RCLG"
7 (:use :common-lisp :uffi :rclg-load )
8 ;; :common-idioms)
9 (:export :start-r :rclg :r :sexp :*backconvert* :*r-started*
10 :r-convert :r-do-not-convert :convert-to-r
11 :sexp-not-needed :update-r :def-r-call :*r-NA* :r-na))
13 (in-package :rclg)
15 (eval-when (:load-toplevel)
16 (unless *rclg-loaded*
17 (error "rclg-load has not loaded the R libraries.")))
19 (eval-when (:compile-toplevel :load-toplevel)
20 (defvar *r-default-argv* '("rclg" "-q" "--vanilla"))
21 (defvar *r-NA-internal* -2147483648) ;; PLATFORM SPECIFIC HACK!!!
22 (defvar *r-na* 'r-na)
24 (defvar +int-seq+ 1)
25 (defvar +float-seq+ 2)
26 (defvar +complex-seq+ 3)
27 (defvar +string-seq+ 4)
28 (defvar +any-seq+ 0))
30 (defvar +seq-fsm+ #2A((0 0 0 0 0)
31 (0 1 2 3 0)
32 (0 2 2 3 0)
33 (0 3 3 3 0)
34 (0 0 0 0 4)))
38 (defparameter *r-started* nil)
41 ;;; Types
42 (eval-when (:compile-toplevel :load-toplevel)
43 (defmacro def-typed-struct (struct-name type &rest field-names)
44 `(def-struct ,struct-name
45 ,@(mapcar (lambda (n) `(,n ,type)) field-names)))
47 (defmacro def-voidptr-struct (struct-name &rest field-names)
48 "Define a structure in which all elements are of type pointer-to-void."
49 `(def-typed-struct ,struct-name :pointer-void ,@field-names))
51 (defmacro def-r-var (r-name cl-name)
52 `(def-foreign-var (,r-name ,cl-name) sexp "R")))
54 (def-foreign-type foreign-string '(* :unsigned-char))
56 ;;; This struct is bitfields.
57 (def-struct sxpinfo-struct (data :unsigned-int))
59 ;; The structures in the union in the SEXPREC
60 (def-struct primsxp-struct (offset :int))
61 (def-voidptr-struct symsxp-struct pname value internal)
62 (def-voidptr-struct listsxp-struct carval cdrval tagval)
63 (def-voidptr-struct envsxp-struct frame enclos hashtab)
64 (def-voidptr-struct closxp-struct formals body env)
65 (def-voidptr-struct promsxp-struct value expr env)
67 (def-union sexprec-internal-union
68 (primsxp primsxp-struct)
69 (symsxp symsxp-struct)
70 (listsxp listsxp-struct)
71 (envsxp envsxp-struct)
72 (closxp closxp-struct)
73 (promsxp promsxp-struct))
75 (def-struct sexprec
76 (sxpinfo sxpinfo-struct)
77 (attrib :pointer-self)
78 (gengcg-next-node :pointer-self)
79 (gengcg-prev-node :pointer-self)
80 (u sexprec-internal-union))
82 (def-foreign-type sexp (* sexprec))
84 ;;; A holder class for a sexp
85 (defclass sexp-holder ()
86 ((sexp :initarg :sexp)
87 (protected :initarg :protected :initform nil)))
89 (defmethod print-object ((s sexp-holder) stream)
90 (format stream "#<sexp at 0x~16R, ~A>"
91 (pointer-address (slot-value s 'sexp))
92 (if (slot-value s 'protected) 'protected 'unprotected)))
94 ;;; Current best guesses
96 ;; (defmacro uffi::get-slot-value (obj type slot)
97 ;; (let ((obj-sym (gensym)))
98 ;; `(let ((,obj-sym ,obj))
99 ;; (declare (type (sb-alien:alien ,(cadr type)) ,obj-sym))
100 ;; (sb-alien:slot ,obj-sym ,slot))))
102 ;; (defmacro uffi::get-slot-value (obj type slot)
103 ;; `(sb-alien:slot (the (sb-alien:alien (* ,(cadr type))) ,obj)
104 ;; ,slot))
106 ;; (defmacro uffi::get-slot-value (obj type slot)
107 ;; `(sb-alien:slot (the (sb-alien:alien ,(cadr type)) ,obj)
108 ;; ,slot))
110 (defmacro uffi::get-direct-value (obj type slot)
111 `(sb-alien:slot (the (sb-alien:alien ,(cadr type)) ,obj) ,slot))
113 (defun sexptype (robj)
114 "Gets the sexptype of an robj. WARNING: ASSUMES THAT THE TYPE
115 IS STORED IN THE LOW ORDER 5 BITS OF THE SXPINFO-STRUCT, AND THAT
116 IT CAN BE EXTRACTED VIA A 'mod 32' OPERATION! MAY NOT BE PORTABLE."
117 (let ((info (uffi::get-direct-value
118 (get-slot-value robj 'sexprec 'sxpinfo)
119 'sxpinfo-struct 'data)))
120 (mod info 32)))
122 ;; We probably only need a few of these, but as soon as I needed two, I
123 ;; decided to go ahead and type them all in.
124 (def-enum sexptype (:nilsxp :symsxp :listsxp :closxp :envsxp :promsxp :langsxp
125 :specialsxp :builtinsxp :charsxp
126 :lglsxp (:intsxp 13) :realsxp :cplxsxp :strsxp
127 :dotsxp :anysxp :vecsxp :exprsxp :bcodesxp
128 :extptrsxp :weakrefsxp (:funsxp 99)))
130 ;;; Access functions
131 (defmacro r-get-u (sexp)
132 `(get-slot-value ,sexp 'sexprec 'u))
134 (defmacro r-get-listsxp (sexp)
135 `(uffi::get-direct-value (r-get-u ,sexp)
136 'sexprec-internal-union
137 'listsxp))
139 (defun r-car (sexp)
140 (get-slot-value (r-get-listsxp sexp) 'listsxp-struct 'carval))
143 (defun r-test (sexp)
144 (format t "--1--~%")
145 (pprint (type-of sexp))
146 (format t "~%--2--~%")
147 (pprint (type-of (r-get-listsxp sexp)))
148 (format t "~%--3--~%")
149 (pprint (get-slot-value (r-get-listsxp sexp) 'listsxp-struct 'carval))
150 (format t "~%--4--~%")
153 (defun r-setcar (sexp value)
154 (setf (get-slot-value (r-get-listsxp sexp) 'listsxp-struct 'carval)
155 value))
157 ;; (defun r-setcar (sexp value)
158 ;; (uffi::set-slot-value (r-get-listsxp sexp) listsxp-struct 'carval value))
160 (defun r-cdr (sexp)
161 (get-slot-value (r-get-listsxp sexp) 'listsxp-struct 'cdrval))
164 (def-function ("SET_TAG" %set-tag)
165 ((robj sexp)
166 (tag sexp))
167 :returning :void)
169 (def-function ("Rf_length" %rf-length)
170 ((x sexp))
171 :returning :int)
173 (def-function ("SET_VECTOR_ELT" %set-vector-elt)
174 ((x sexp)
175 (i :int)
176 (v sexp))
177 :returning sexp)
179 (def-function ("Rf_elt" %rf-elt)
180 ((s sexp)
181 (i :int))
182 :returning sexp)
184 (def-function ("VECTOR_ELT" %vector-elt)
185 ((s sexp)
186 (i :int))
187 :returning sexp)
189 (def-function ("Rf_coerceVector" %rf-coerce-vector)
190 ((s sexp)
191 (type sexptype))
192 :returning sexp)
194 ;;; Allocation and Protection
196 (def-function ("Rf_allocVector" %rf-alloc-vector)
197 ((s sexptype)
198 (n :int))
199 :returning sexp)
201 ;; def-function doesn't take a docstring! "'Protects' the item
202 ;; (presumably by telling the garbage collector it's in use, although
203 ;; I haven't looked at the internals. Returns the same pointer you
204 ;; give it."
205 (def-function ("Rf_protect" %rf-protect)
206 ((s sexp))
207 :returning sexp)
209 (def-function ("Rf_unprotect" %rf-unprotect)
210 ((n :int))
211 :returning :void)
213 (def-function ("Rf_unprotect_ptr" %rf-unprotect-ptr)
214 ((s sexp))
215 :returning :void)
217 (defun sexp-not-needed (poss-sexp)
218 (when (and (typep poss-sexp 'sexp-holder)
219 (slot-value poss-sexp 'protected))
220 (%rf-unprotect-ptr (slot-value poss-sexp 'sexp))
221 (setf (slot-value poss-sexp 'protected) nil))
222 poss-sexp)
225 ;;; Variables
227 (def-r-var "R_GlobalEnv" *r-global-env*)
228 (def-r-var "R_UnboundValue" *r-unbound-value*)
229 (def-r-var "R_NilValue" *r-nil-value*)
231 ;;; Foreign string handling.
233 (defun stringseq-to-foreign-string-array (stringseq)
234 (let ((n (length stringseq)))
235 (let ((res (uffi:allocate-foreign-object 'foreign-string n)))
236 (dotimes (i n)
237 (setf (deref-array res '(:array foreign-string) i)
238 (convert-to-foreign-string (elt stringseq i))))
239 (values res n))))
241 (defmacro with-foreign-string-array ((name length str-array) &body body)
242 (let ((ctr (gensym)))
243 `(multiple-value-bind (,name ,length) (stringseq-to-foreign-string-array ,str-array)
244 (unwind-protect
245 ,@body
246 (progn
247 (dotimes (,ctr ,length)
248 (free-foreign-object (deref-array ,name '(:array foreign-string) ,ctr)))
249 (free-foreign-object ,name))))))
251 ;;; R initialization
253 (def-function ("Rf_initEmbeddedR" %rf-init-embedded-r)
254 ((argc :int)
255 (argv (* foreign-string)))
256 :returning :int)
258 (defun start-r (&optional (argv *r-default-argv*))
259 (unless *r-started*
260 (setf *r-started*
261 (with-foreign-string-array (foreign-argv n argv)
262 (%rf-init-embedded-r n foreign-argv)))))
264 ;;; R evaluation
266 (def-function ("Rf_findVar" %rf-find-var)
267 ((installed sexp)
268 (environment sexp))
269 :returning sexp)
271 (def-function ("Rf_install" %rf-install)
272 ((ident foreign-string))
273 :returning sexp)
275 (def-function ("R_tryEval" %r-try-eval)
276 ((e sexp)
277 (env sexp)
278 (error-occurred (* :int)))
279 :returning sexp)
281 (defun r-eval (expr)
282 (with-foreign-object (e :int)
283 (setf (deref-pointer e :int) 0)
284 (let ((res (%r-try-eval expr *r-global-env* e)))
285 (if (not (= (deref-pointer e :int) 0))
286 (error "Bad expr: ~A" (get-r-error))
287 res))))
289 (defun r-bound (robj)
290 "Checks to see if an R SEXP is (has the address of) the *r-unbound-value* SEXP."
291 (not (= (pointer-address robj)
292 (pointer-address *r-unbound-value*))))
294 (defun r-nil (robj)
295 "Checks to see if an R SEXP is (has the address of) the *r-nil-value* SEXP."
296 (= (pointer-address robj)
297 (pointer-address *r-nil-value*)))
299 (defun get-from-name-test (name)
300 (declare (type simple-string name))
301 (CONVERT-TO-FOREIGN-STRING NAME))
304 ;; (installed (%rf-install ident-foreign)))
307 ;; (G1360
308 ;; (PROGN
309 ;; (let (
310 ;; (values)))))))
312 ;; (LET ((FOREIGN-VALUE
313 ;; (%RF-FIND-VAR (%RF-INSTALL IDENT-FOREIGN) *R-GLOBAL-ENV*)))
314 ;; (values)))))))
316 ;; (IF (R-BOUND FOREIGN-VALUE) FOREIGN-VALUE NIL)))))
317 ;; (values)))
318 ;; (DECLARE (DYNAMIC-EXTENT IDENT-FOREIGN))
319 ;; (FREE-FOREIGN-OBJECT IDENT-FOREIGN)
320 ;; G1360))
322 (defun get-from-name (name)
323 "If R has a mapping for name (name is a string), returns the SEXP that points to it,
324 otherwise returns NIL."
325 (with-foreign-string (ident-foreign name)
326 (let ((foreign-value
327 (%rf-find-var (%rf-install ident-foreign) *r-global-env*)))
328 (if (r-bound foreign-value)
329 foreign-value
330 nil))))
332 (def-function ("Rf_getAttrib" %rf-get-attrib)
333 ((robj sexp)
334 (attrib sexp))
335 :returning sexp)
337 (def-function ("Rf_setAttrib" %rf-set-attrib)
338 ((robj sexp)
339 (attrib sexp)
340 (val sexp))
341 :returning sexp)
343 (def-r-var "R_NamesSymbol" *r-names-symbol*)
344 (def-r-var "R_DimSymbol" *r-dims-symbol*)
346 ;;; Basic conversions
348 (def-function ("LOGICAL" %LOGICAL)
349 ((e sexp))
350 :returning (* :int))
352 (def-function ("INTEGER" %INT)
353 ((e sexp))
354 :returning (* :int))
356 (def-function ("REAL" %REAL)
357 ((e sexp))
358 :returning (* :double))
360 ;; (DEFUN %REAL (E)
361 ;; (SB-ALIEN:WITH-ALIEN ((%REAL (FUNCTION (* C-CALL:DOUBLE) SEXP) :EXTERN "REAL"))
362 ;; (VALUES (SB-ALIEN:ALIEN-FUNCALL %REAL E))))
365 ;;; The complex type
366 (def-struct r-complex
367 (r :double)
368 (i :double))
370 (def-function ("COMPLEX" %COMPLEX)
371 ((e sexp))
372 :returning (* 'r-complex))
374 ;;; String handling.
375 (def-function ("Rf_mkChar" %rf-mkchar)
376 ((s foreign-string))
377 :returning sexp)
379 (def-function ("SET_STRING_ELT" %set-string-elt)
380 ((robj sexp)
381 (i :int)
382 (string sexp))
383 :returning :void)
385 (def-function ("STRING_ELT" %string-elt)
386 ((s sexp)
387 (i :int))
388 :returning sexp)
390 (def-function ("R_CHAR" %r-char)
391 ((s sexp))
392 :returning foreign-string)
394 ;;; Basic Conversion Routines
396 (defun robj-to-int (robj &optional (i 0))
397 "Returns the integer inside an R object. Assumes it's an
398 integral robj. Converts NA's"
399 (let ((result (deref-array (%INT robj) :int i)))
400 (if (= result *r-NA-internal*)
401 *r-NA*
402 result)))
404 (defun robj-to-logical (robj &optional (i 0))
405 "Returns the logical inside an R object. Assumes it's an
406 logical robj."
407 (= 1 (robj-to-int robj i)))
409 (defun robj-to-double (robj &optional (i 0))
410 "Returns the double-float inside an R object. Assumes it's an
411 double-float robj."
412 (declare (type fixnum i))
413 (deref-array (%real robj) :double i))
416 (defun robj-to-complex (robj &optional (i 0))
417 "Returns the complex number inside an R object. Assumes it's a
418 complex robj."
419 (let ((complex (deref-array (%COMPLEX robj) 'r-complex i)))
420 (complex (uffi::get-direct-value complex 'r-complex 'r)
421 (uffi::get-direct-value complex 'r-complex 'i))))
423 (defun robj-to-string (robj &optional (i 0))
424 "Convert an R object to a string. Assumes it's a string robj."
425 (convert-from-foreign-string (%r-char (%string-elt robj i))))
427 ;;; Helpers
429 (def-function ("doubleFloatVecToR" %double-float-vec-to-R)
430 ((d (* :double))
431 (i :int)
432 (s sexp))
433 :returning :void)
435 (def-function ("intVecToR" %integer-vec-to-R)
436 ((d (* :int))
437 (i :int)
438 (s sexp)
439 (div :int))
440 :returning :void)
444 ;;; Sequence and (eventually) Dictionary Conversions
447 (defun type-to-int (obj)
448 (cond ((eql obj *r-na*) +int-seq+)
449 (t (typecase obj
450 (integer +int-seq+)
451 (float +float-seq+)
452 (complex +complex-seq+)
453 (string +string-seq+)
454 (t +any-seq+)))))
456 (defun sequence-to-robj (seq)
457 (let ((len (length seq)))
458 (let ((robj (%rf-protect (%rf-alloc-vector sexptype#vecsxp len)))
459 (state (type-to-int (elt seq 0)))
460 (i 0))
461 (typecase seq
462 ((simple-array double-float)
463 (%double-float-vec-to-R (sb-sys:vector-sap seq) len robj))
465 ;; (map nil
466 ;; (lambda (e)
467 ;; (%set-vector-elt robj i (double-float-to-robj e))
468 ;; (incf i))
469 ;; seq))
471 ((simple-array fixnum)
472 (%integer-vec-to-R (sb-sys:vector-sap seq) len robj 4))
474 (map nil
475 (lambda (e)
476 (%set-vector-elt robj i (convert-to-r e))
477 (setf state (aref +seq-fsm+ state (type-to-int e))
478 i (+ i 1)))
479 seq)))
480 (let ((result
481 (case state
482 (#.+int-seq+ (%rf-coerce-vector robj sexptype#intsxp))
483 (#.+float-seq+ (%rf-coerce-vector robj sexptype#realsxp))
484 (#.+complex-seq+ (%rf-coerce-vector robj sexptype#cplxsxp))
485 (#.+string-seq+ (%rf-coerce-vector robj sexptype#strsxp))
486 (t robj))))
487 (%rf-unprotect 1)
488 (values result state)))))
491 (defgeneric convert-to-r (value)
492 (:method ((n null)) *r-nil-value*)
493 (:method ((i integer)) (int-to-robj i))
494 (:method ((f float)) (float-to-robj f))
495 (:method ((d double-float)) (double-float-to-robj d))
496 (:method ((c complex)) (complex-to-robj c))
497 (:method ((s string)) (string-to-robj s))
498 (:method ((s sequence)) (sequence-to-robj s))
499 (:method ((s sexp-holder)) (slot-value s 'sexp))
500 (:method ((v vector)) (sequence-to-robj v))
501 (:method ((a array)) (array-to-robj a))
502 (:method ((k symbol)) k)) ;; for keywords or for T
504 (defmethod convert-to-r ((na (eql *r-NA*)))
505 (convert-to-r *r-NA-internal*))
508 (defmethod convert-to-r ((l (eql t)))
509 "Returns an R object corresponding to the logical t."
510 (let ((robj (%rf-alloc-vector sexptype#lglsxp 1)))
511 (setf (deref-pointer (%LOGICAL robj) :int)
513 robj))
516 (defun int-to-robj (n)
517 "Returns an R object corresponding to an integer."
518 (let ((robj (%rf-alloc-vector sexptype#intsxp 1)))
519 (setf (deref-pointer (%INT robj) :int) n)
520 robj))
523 (defun float-to-robj (f)
524 "Returns an R object corresponding to a floating point number. Coerces
525 the number to double-float."
526 (double-float-to-robj (coerce f 'double-float)))
529 (defun double-float-to-robj (d)
530 "Returns an R object corresponding to a floating point number. Coerces
531 the number to double-float."
532 (let ((robj (%rf-alloc-vector sexptype#realsxp 1)))
533 (setf (deref-pointer (%real robj) :double) d)
534 robj))
536 (defun complex-to-robj (c)
537 "Returns an R object corresponding to a CL complex number. Coerces the
538 real and imaginary points to double-float."
539 (let ((robj (%rf-alloc-vector sexptype#cplxsxp 1)))
540 (let ((complex (deref-pointer (%COMPLEX robj) 'r-complex)))
541 ;; (setf (get-slot-value complex 'r-complex 'r) (coerce (realpart c) 'double-float)
542 ;; (get-slot-value complex 'r-complex) 'i) (coerce (imagpart c) 'double-float)))
543 (setf (sb-alien:slot complex 'r) (coerce (realpart c) 'double-float)
544 (sb-alien:slot complex 'i) (coerce (imagpart c) 'double-float)))
545 robj))
547 (defun string-to-robj (string)
548 "Convert a string to an R object."
549 (let ((robj (%rf-alloc-vector sexptype#strsxp 1))
550 (str-sexp
551 (with-foreign-string (s string)
552 (%rf-mkchar s))))
553 (%set-string-elt robj 0 str-sexp)
554 robj))
556 (defun array-to-robj (a)
557 "Convert an array to an R object."
558 (let ((column-vector
559 (convert-to-r (array-to-vec-column-major a))))
560 (%rf-set-attrib column-vector
561 *r-dims-symbol*
562 (convert-to-r (array-dimensions a)))
563 column-vector))
565 (defun convert-from-r (robj)
566 "Attempt to convert a general R value to a CL value."
567 (if (r-nil robj)
569 (let ((length (%rf-length robj)))
570 (if (= length 0)
572 (let ((result (convert-from-r-seq robj length)))
573 (if (= length 1)
574 (aref result 0)
575 result))))))
577 (defun sexptype-to-element-type (type)
578 (case type
579 (#.sexptype#intsxp 'integer) ;;; Sigh, not fixnum.
580 (#.sexptype#lglsxp 'boolean)
581 (#.sexptype#realsxp 'double-float)
582 (#.sexptype#cplxsxp 'complex)
583 (#.sexptype#strsxp 'string)
584 (#.sexptype#listsxp 't)
585 (#.sexptype#vecsxp 't)
586 (t (error "Unknown type"))))
588 (defun convert-from-r-seq (robj length)
589 "Convert an r-sequence into CL."
590 (let* ((type (sexptype robj))
591 (result (make-array length :element-type (sexptype-to-element-type type))))
592 (dotimes (i length)
593 (setf (aref result i)
594 (case type
595 (#.sexptype#intsxp (robj-to-int robj i))
596 (#.sexptype#lglsxp (robj-to-logical robj i))
597 (#.sexptype#realsxp (robj-to-double robj i))
598 (#.sexptype#cplxsxp (robj-to-complex robj i))
599 (#.sexptype#strsxp (robj-to-string robj i))
600 (#.sexptype#listsxp (convert-from-r (%rf-elt robj i)))
601 (#.sexptype#vecsxp (convert-from-r (%vector-elt robj i)))
602 (t (error "Unknown type")))))
603 (values result type)))
605 (defmacro get-name (symbol-or-string)
606 (if (stringp symbol-or-string)
607 symbol-or-string
608 (string-downcase (symbol-name symbol-or-string))))
610 (eval-when (:compile-toplevel :load-toplevel)
611 (defparameter *backconvert* t)
615 (defun to-list (seq)
616 (map 'list #'identity seq))
618 (defun to-vector (seq)
619 (map 'vector #'identity seq))
622 (defmacro r-convert (&body body)
623 (let ((*backconvert* t)) ;; Compile time
624 `(let ((*backconvert* t)) ;; Run time
625 ,@body)))
627 (defmacro r-do-not-convert (&body body)
628 (let ((*backconvert* nil)) ;; Compile time
629 `(let ((*backconvert* nil)) ;; Run time
630 ,@body)))
632 (defmacro with-r-args ((name &rest arglist) &body body)
633 `(let ((,name (get-r-args ,@arglist)))
634 (unwind-protect
635 (multiple-value-prog1 ,@body)
636 (unprotect-args ,name))))
638 (defmacro with-gensyms (syms &body body)
639 `(let (,@(mapcar (lambda (sy)
640 `(,sy (gensym ,(symbol-name sy))))
641 syms))
642 ,@body))
644 (defmacro r (name &rest args)
645 "The primary user interface to rclg. Converts all the arguments into
646 R objects. Does not backconvert nested calls to R, so a call like
647 r sum (r seq 1 10)) should DTRT."
648 (with-gensyms (r-args evaled result names dims)
649 `(with-r-args (,r-args ,@args)
650 (let ((,evaled (%rf-protect (r-call (get-name ,name) ,r-args))))
651 (update-r)
652 ,(if *backconvert*
653 `(let ((,result (convert-from-r ,evaled))
654 (,names (r-names ,evaled))
655 (,dims (r-dims ,evaled)))
656 (%rf-unprotect 1) ;; evaled
657 (values (if ,dims (reshape-array ,result ,dims) ,result)
658 ,names))
659 `(make-instance 'sexp-holder :sexp ,evaled :protected t))))))
662 (defmacro get-r-args (&rest args)
663 `(r-do-not-convert
664 (list ,@(mapcar (lambda (a)
665 (if (keywordp a)
667 `(%rf-protect (convert-to-r ,a))))
668 args))))
670 (defun unprotect-args (args)
671 (map nil (lambda (a) (unless (keywordp a) (%rf-unprotect-ptr a))) args))
673 (defun r-call (name args)
674 "Does the actual call to R. The args must be a list of raw
675 R objetcs. Returns an unprotected, unconverted R object."
676 (let ((func (get-from-name name)))
677 (if (not func)
678 (error "Cannot find function ~A" name)
679 (let ((func (%rf-protect func))
680 (exp (%rf-protect
681 (%rf-alloc-vector sexptype#langsxp (sexp-length args)))))
682 (r-setcar exp func)
683 (%rf-unprotect 1) ;; func
684 (parse-args (r-cdr exp) args)
685 (r-eval exp)))))
687 (defun get-r-error ()
688 (r-convert
689 (r geterrmessage)))
691 (defun parse-args (exp args)
692 (do ((arglist args (cdr arglist)))
693 ((null arglist) nil)
694 (let ((cur (car arglist)))
695 (if (keywordp cur)
696 (progn
697 (parse-keyword exp cur (cadr arglist))
698 (setf arglist (cdr arglist)))
699 (parse-regular-arg exp cur))
700 (with-cast-pointer (r-cur exp 'sexprec)
701 (setf exp (r-cdr r-cur))))))
703 (defun parse-keyword (exp kwd arg)
704 (with-cast-pointer (p exp 'sexprec)
705 (r-setcar p arg)
706 (with-foreign-string (f (string-downcase (symbol-name kwd)))
707 (%set-tag p (%rf-install f)))))
709 (defun parse-regular-arg (exp arg)
710 (with-cast-pointer (p exp 'sexprec)
711 (r-setcar p arg)))
713 (defmacro over-column-major-indices ((array cmi rmi) &body body)
714 (with-gensyms (n index dims update-index dim d index-param)
715 `(let* ((,n (array-total-size ,array))
716 (,dims (to-vector (array-dimensions ,array)))
717 (,d (array-rank ,array))
718 (,index (to-list (make-array ,d :initial-element 0))))
719 (labels ((,update-index (,index-param ,dim)
720 (incf (car ,index-param))
721 (when (= (car ,index-param) (aref ,dims ,dim))
722 (setf (car ,index-param) 0)
723 (when (< ,dim (- ,d 1))
724 (,update-index (cdr ,index-param) (+ ,dim 1))))))
725 (dotimes (,rmi ,n)
726 (let ((,cmi (apply #'array-row-major-index ,array ,index)))
727 ,@body
728 (,update-index ,index 0)))))))
730 (defun reshape-array (old-array dims)
731 (let ((result (make-array (to-list dims) :element-type (array-element-type old-array))))
732 (over-column-major-indices (result cmi rmi)
733 (setf (row-major-aref result cmi) (aref old-array rmi)))
734 result))
736 (defun array-to-vec-column-major (array)
737 (let ((result (make-array (array-total-size array) :element-type (array-element-type array))))
738 (over-column-major-indices (array cmi rmi)
739 (setf (aref result rmi) (row-major-aref array cmi)))
740 result))
742 (defun sexp-length (args)
743 (+ 1 (length args) (- (count-keywords args))))
745 (defun count-keywords (args)
746 (count-if #'keywordp args))
748 (defun r-names (robj)
749 (let ((names (%rf-get-attrib robj *r-names-symbol*)))
750 (if (r-nil names)
752 (convert-from-r names))))
754 (defun r-dims (robj)
755 (let ((dims (%rf-get-attrib robj *r-dims-symbol*)))
756 (if (r-nil dims)
758 (convert-from-r dims))))
761 ;;; Event handling
763 (def-foreign-type input-handler-ptr (* :void))
764 (def-foreign-type fd-mask (* :void))
766 (def-foreign-var ("R_InputHandlers" *r-input-handlers*) input-handler-ptr "R")
769 (def-function ("R_checkActivity" %r-check-activity)
770 ((usec :int)
771 (ignore-stdin :int))
772 :returning fd-mask)
774 (def-function ("R_runHandlers" %r-run-handlers)
775 ((i input-handler-ptr)
776 (f fd-mask))
777 :returning :void)
779 ;;; Primarily for updating graphics
780 (defun update-R ()
781 (%r-run-handlers *r-input-handlers*
782 (%r-check-activity 10000 0)))
785 (defun remove-plist (plist &rest keys)
786 "Remove the keys from the plist.
787 Useful for re-using the &REST arg after removing some options."
788 (do (copy rest)
789 ((null (setq rest (nth-value 2 (get-properties plist keys))))
790 (nreconc copy plist))
791 (do () ((eq plist rest))
792 (push (pop plist) copy)
793 (push (pop plist) copy))
794 (setq plist (cddr plist))))
796 (defun to-keyword (symbol)
797 (intern (symbol-name symbol) :keyword))
799 (defun atom-or-first (val)
800 (if (atom val)
802 (car val)))
804 (defmacro def-r-call ((macro-name r-name conversion &rest required-args)
805 &rest keyword-args)
806 (let* ((rest-sym (gensym "rest"))
807 (result-sym (gensym "result"))
808 (keyword-names (mapcar #'atom-or-first keyword-args))
809 (keywords (mapcar #'to-keyword keyword-names)))
810 `(defmacro ,macro-name (,@required-args
811 &rest ,rest-sym
812 &key ,@keyword-args
813 &allow-other-keys)
814 `(let ((,',result-sym
815 (r-do-not-convert
816 (r ,',r-name
817 ,,@required-args
818 ,,@(mapcan #'(lambda (k n) (list k n))
819 keywords
820 keyword-names)
821 ,@(remove-plist ,rest-sym ,@keywords)))))
822 (declare (ignorable ,',result-sym))
823 ,',(case conversion
824 (:convert `(r-convert ,result-sym))
825 (:raw `,result-sym)
826 (:no-result nil)
827 (t (error "Unknown value of conversion: ~A" conversion)))))))
829 ;; This is necessary because CMU's traps modes cause error upon
830 ;; R startup.
831 #+sbcl
832 (eval-when (:load-toplevel)
833 (sb-int:set-floating-point-modes :traps (list :overflow)))
835 ;; (eval-when (:load-toplevel)
836 ;; (let ((current-traps (cadr (member :traps (sb-int:get-floating-point-modes)))))
837 ;; (when (find :invalid current-traps)
838 ;; (progn
839 ;; (warn "WARNING: removing :invalid from floating-point-modes traps.")
840 ;; (sb-int:set-floating-point-modes :traps
841 ;; (remove :invalid current-traps))))))
844 (eval-when (:load-toplevel)
845 (start-r))
847 #+cmu
848 (eval-when (:load-toplevel)
849 (mp:make-process (lambda () (do () (nil) (progn (update-r) (sleep 0.1))))))
851 (defmacro uffi::get-slot-value (obj type slot)
852 `(sb-alien:slot ,obj ,slot))