2 ;; see example of specification at end of this file.
4 ;;for maxima g(t,u) == (($g simp) $t $u)
5 ;; (coerce-call-lisp '(($g simp) $t $u)) --> ($g $t $u)
6 (defun coerce-call-lisp (fcall)
7 (cond ((atom fcall
) fcall
)
10 (cond ((eq (caar fcall
) 'mlist
)
11 (mapcar 'coerce-call-lisp
(cdr fcall
)))
12 (t (cons (caar fcall
) (cdr fcall
)))))
15 (defvar *fortran-types
*)
16 (setq *fortran-types
* '(($integer .
"int")
18 ($dimension .
"dimension")
19 ($external .
"void *")
23 (defun get-fortran-type (type)
24 (or (cdr (assoc type
*fortran-types
*)) (error "unrecognized type ~a " type
)))
27 (defvar $fortran_force_new_compile nil
)
28 (defvar $fortran_path
'((mlist) "./" "/usr/local/lib/linpack/"))
32 (defmacro $make_fortran
(fun declarations
&rest l
&aux path tem locals
)
33 (let ((keys (parse_keys l
'($defaults $result $assertions $locals $requires_subroutines
36 (setq fun
(coerce-call-lisp fun
))
37 (setq declarations
(coerce-call-lisp declarations
))
39 (let ((result (coerce-call-lisp (cadr (assoc '$result keys
))))
40 (defaults (cadr (assoc '$defaults keys
)))
41 (assertions (cadr (assoc '$assertions keys
)))
42 (locals (cadr (assoc '$locals keys
)))
43 (name (with-output-to-string (*fortran-out
*)(wt (car fun
))))
44 (requires_subroutines (cadr (assoc '$requires_subroutines
)))
45 (libs (if (assoc '$libs
)
46 (coerce (mstring(cadr (assoc '$libs
))) 'string
)
53 (or $fortran_force_new_compile
55 (dolist (v (cdr $fortran_path
))
56 (if (probe-file (setq tem
(si::string-concatenate v name
58 (return (setq path
(namestring (truename tem
))))))))
60 (make-fortran-fun fun declarations result name locals
)
62 (compiler::safe-system
63 (si::string-concatenate
64 "cc -c -O " name
".c ; "
65 "cc -L/usr/local/lib " libs
66 " -L/usr/lang/SC1.0 -lF77 -lm fony.o -o " name
".exe " name
".o"
67 ;";rm -f " name ".o " name ".c "
69 (setq path
(namestring
70 (truename (si::string-concatenate name
".exe")))))
71 (define-maxima-function fun declarations defaults result path assertions
)
72 (list 'quote
(car fun
)))))
74 (defstruct fortran args requireds decls defaults results exec-path assertions
79 (defun default-type-value (type) (or (cdr (assoc type
'(($integer .
0)
82 (error "no default for ~a" type
)))
84 (defun $default_array
(type dim1
&optional dim2
&aux res
)
85 (or (and (typep dim1
'fixnum
)
86 (or (null dim2
) (typep dim2
'fixnum
)))
87 (error "dimension not fixnum"))
88 (cond ((null dim2
) (cons '(mlist)(make-list dim1
:initial-element
89 (default-type-value type
))))
92 (push ($default_array type dim2
) res
))))))
94 (defun maxima-defaults (deflt )
95 (declare (special *decls
*))
96 (cond ((and (consp deflt
)
98 (eq (caar deflt
) 'mequal
))
100 ((and (symbolp deflt
)
101 (let* ((type (cdr (get-arg-decl deflt
*decls
*)))
102 (tem (if (atom type
) (default-type-value type
)
103 `(($default_array
) ,@ type
))))
104 (and tem
(list '(mequal) deflt tem
)))))
106 (error "don't know how to give default to ~a" deflt
))))
108 (defun define-maxima-function (fun declarations defaults results path
110 (let (args (*decls
* declarations
))
111 (declare (special *decls
*))
112 (setq defaults
(mapcar 'maxima-defaults
(cdr defaults
)))
113 (dolist (v (cdr fun
) (setq args
(nreverse args
)))
114 (or (find v defaults
:key
'cadr
) (push v args
)))
115 (setf (get (car fun
) 'fortran
) (make-fortran :args
(cdr fun
)
120 :results
(or results
(cdr fun
))
122 :assertions assertions
125 (setf (get (car fun
) 'mfexpr
*)
126 #'(LAMBDA (FORTRAN-ARG) (MAXIMA-FORTRAN-INVOKE FORTRAN-ARG
)))
129 (defvar $tmp_prefix nil
)
130 (defun get-temp-path (prefix suffix
&aux tem
)
132 (unless (probe-file (setq tem
(format nil
"~a~a" prefix i suffix
)))
136 (defun link-with-subroutines (f arg-values
&aux fun name
)
137 (let ((subrs (fortran-subroutines f
)))
138 (sloop for v in
(cdr (fortran-subroutines f
))
139 do
(or ($listp v
) (error "subr decl should be list ~M" v
))
142 (symbolp (caar fun
)))
143 (merror "bad declaration ~M" v
))
144 (setq name
(caar fun
))
145 (let* ((keys (parse_keys (cddr v
) '($decls
) nil nil
))
146 (decls (nth 2 (assoc '$decls keys
)))
147 (val (nth (position name
(fortran-args f
)) arg-values
)))
149 (setq def
(mget '$ff
'mexpr
)))
158 (defun maxima-fortran-invoke (arg &aux arg-values tem io-path exec-path
)
159 (or $tmp_prefix
(setq $tmp_prefix
(format nil
"/tmp/~a_fort"
160 (si::getenv
"USER"))))
161 (let* ((f (get (caar arg
) 'fortran
))
164 (+ (length (fortran-requireds f
)) 1))
168 (cond ((eql (length arg
) default-pos
)
169 (fortran-defaults f
))
170 ((eql (length arg
) (+ 1 default-pos
))
171 (or ($listp
(nth default-pos arg
))
172 (error "defaults not a list"))
174 (append (mapcar 'maxima-defaults
175 (cdr(nth default-pos arg
)))
176 (fortran-defaults f
))
177 (setq arg
(butlast arg
))))
178 (t (error "~a needs ~a or ~a args" (caar arg
)(- default-pos
1)
179 (- default-pos
2))))))
180 (progv (fortran-requireds f
)
181 (mapcar 'meval
* (cdr arg
))
183 (setq defaults
(parse_keys defaults
(Fortran-args f
)
185 (dolist (v (fortran-args f
))
186 (if (setq tem
(assoc v defaults
))
187 (push (list v
(second tem
)) arg-values
)
188 (push (list v
(symbol-value v
)) arg-values
))))
189 (setq arg-values
(nreverse arg-values
))
191 (if (fortran-subroutines f
)
192 (link-with-subroutines f arg-values
)
193 (fortran-exec-path f
)))
195 (with-open-file (st (setq io-path
(get-temp-path $tmp_prefix
"Fw"))
197 (let ((xdr (si::xdr-open st
)))
198 (dolist (v arg-values
)
199 (push (maxima-coerce-to-xdr
201 (cdr (get-arg-decl (car v
)
204 (si::xdr-write xdr
(car arg-values-c
)))))
205 (setq arg-values-c
(nreverse arg-values-c
))
207 (format nil
" ~a < ~a > ~ao ; rm -f ~a"
209 io-path io-path io-path
212 (with-open-file (st (setq io-path
(concatenate 'string io-path
"o")))
213 (let ((xdr (si::xdr-open st
))
214 (pairs (pairlis (fortran-args f
) arg-values-c
))
216 (dolist (v (fortran-results f
))
217 (push (si::xdr-read xdr
(cdr (assoc v pairs
))) result
))
218 (setq result
(nreverse result
))
220 (sloop::sloop for v in result
221 for na in
(fortran-results f
)
223 (coerce-maxima-from-xdr v
230 (delete-file io-path
)
234 #+when-run-process-deallocates
235 (defun maxima-fortran-invoke (arg &aux arg-values tem
)
236 (let* ((f (get (caar arg
) 'fortran
))
239 (+ (length (fortran-requireds f
)) 1))
241 (cond ((eql (length arg
) default-pos
)
242 (fortran-defaults f
))
243 ((eql (length arg
) (+ 1 default-pos
))
244 (or ($listp
(nth default-pos arg
))
245 (error "defaults not a list"))
247 (append (mapcar 'maxima-defaults
248 (cdr(nth default-pos arg
)))
249 (fortran-defaults f
))
250 (setq arg
(butlast arg
))))
251 (t (error "~a needs ~a or ~a args" (caar arg
)(- default-pos
1)
252 (- default-pos
2))))))
253 (progv (fortran-requireds f
)
254 (mapcar 'meval
* (cdr arg
))
256 (setq defaults
(parse_keys defaults
(Fortran-args f
)
258 (dolist (v (fortran-args f
))
259 (if (setq tem
(assoc v defaults
))
260 (push (list v
(second tem
)) arg-values
)
261 (push (list v
(symbol-value v
)) arg-values
))))
262 (setq arg-values
(nreverse arg-values
))
263 (let* ((tem (si::run-process
(fortran-exec-path f
) nil
))
264 (out (si::fp-output-stream tem
))
265 (in (si::fp-input-stream tem
)))
266 (let ((xdr (si::xdr-open out
)))
267 (dolist (v arg-values
)
268 (push (maxima-coerce-to-xdr (second v
)
269 (cdr (get-arg-decl (car v
)
273 (si::xdr-write xdr
(car arg-values-c
))))
274 (setq arg-values-c
(nreverse arg-values-c
))
277 (let ((xdr (si::xdr-open in
))
278 (pairs (pairlis (fortran-args f
) arg-values-c
))
280 (dolist (v (fortran-results f
))
281 (push (si::xdr-read xdr
(cdr (assoc v pairs
))) result
))
282 (setq result
(nreverse result
))
284 (sloop::sloop for v in result
285 for na in
(fortran-results f
)
287 (coerce-maxima-from-xdr v
292 (defun meval-* (lis &aux tem
)
293 (cond ((null lis
) lis
)
294 (t (progv (list (caar lis
))
295 (list (setq tem
(meval* (second (car lis
)))))
296 (cons (list (caar lis
) tem
)
297 (meval-* (cdr lis
)))))))
300 ;; return an list of (list keys value)
301 ;; where each value is meval* in with previous keys bound to
303 (defun parse_keys (list keys meval done
&aux sym tem
)
304 (cond ((null list
) done
)
306 (consp (setq tem
(car list
)))
308 (eq (caar tem
) 'mequal
)
309 (or (eq keys
'$allow_any_key
)
311 (member (setq sym
(second tem
)) keys
)))
313 (cond ((assoc sym done
)
314 (parse_keys (cdr list
) keys meval done
))
318 (setq tem
(if meval
(meval* (third (car list
)))
319 (third (car list
)))))
320 (setq done
(nconc done
(list (list sym tem
))))
321 (parse_keys (cdr list
) keys meval done
)))))
322 ((error "unrecognized key = ~a" (or sym tem
)))))
325 (defvar *lisp-types
* '(($double . long-float
) ($integer . fixnum
)
326 ($single . short-float
)))
328 (defun maxima-coerce-to-xdr (v decl
)
331 ($double
(coerce v
'long-float
))
332 ($single
(coerce v
'short-float
))
333 ($external
(coerce v
'fixnum
))
334 (t (cond ((consp decl
)
335 (let* ((dim (cond ((atom (second v
)) ($length v
))
336 (t (* ($length v
) ($length
(second v
))))))
337 (ar (lisp::make-array dim
:static t
338 :element-type
(cdr (assoc (car decl
)
340 (or (numberp (aref ar
0)) (error "bad array type"))
341 (maxima-flatten ($transpose v
) ar
0)
343 (t (error "unknown type"))))))
345 (defun maxima-flatten (v ar i
)
348 (cond ((mbagp (second v
))
350 (setq i
(maxima-flatten w ar i
))))
351 (t (dolist (u (cdr v
))
355 (t (error "bad elt"))))
357 (defun coerce-maxima-from-xdr (v elt
)
358 (setq elt
(second elt
))
362 (cond ((and ($listp elt
) (numberp (second elt
)))
363 (cons '(mlist) (coerce v
'list
)))
365 (let ((n (length (cdr elt
)))
369 (sloop for i below
(floor (length v
) n
)
377 (setq ans
($transpose ans
))))
378 (t (error "unkown type"))))))
383 ;; variables to forget from names
384 (defvar *forget
* '(#\$
))
385 (defvar *fortran-out
* nil
)
386 (defun wt1 (x &aux
(ch #\a))
387 (declare (character ch
))
389 (dotimes (i (length (symbol-name x
)))
391 (setq ch
(schar (symbol-name x
) i
))
392 (if (member ch
*forget
*) nil
393 (princ (char-downcase ch
) *fortran-out
*))))
395 (princ x
*fortran-out
*))
396 (t (princ x
*fortran-out
*))))
398 (defmacro wt
(&rest l
&aux lis
)
399 `(progn ,@ (dolist (v l
(nreverse lis
)) (push `(wt1 ,v
) lis
))))
401 (defmacro wt-nl
(&rest l
)
402 `(progn (terpri *fortran-out
*)(wt1 " ") (wt ,@l
)))
405 (defun get-arg-decl (arg decls
&aux size tem
)
406 (cond ((setq tem
(assoc '$dimension decls
))
407 (dolist (v (cdr tem
))
408 (when (and (consp v
) (eq (car v
) arg
))
414 (if (eq u arg
) (return-from get-arg-decl
420 (return-from get-arg-decl
(cons arg
(cons (car v
) (cdr u
))))))))
421 (error "undeclared arg ~a" arg
))
423 (defun xdr-fun (type)
424 (if (consp type
) "array"
425 (or (cdr (assoc type
'(($integer .
"int")
427 ($complex .
"double")
431 (error "unknown type ~a" type
))))
433 (defun wt-xdr (v stream
)
434 (wt-nl "CHECK(xdr_" (xdr-fun (cdr v
))"(" stream
",")
436 (cond ((consp (cdr v
))
437 (wt ",&" (car v
)"_length, MAX_ARRAY("(car v
)"_length),")
438 (wt-nl " sizeof(" (get-fortran-type (second v
)) "),xdr_"
439 (xdr-fun (cadr v
)))))
443 (defun make-fortran-fun (fun+args decls results name locals
)
444 (let ((file (concatenate 'string name
".c"))
445 (args (cdr fun
+args
)))
446 (or results
(setq results
(cdr fun
+args
)))
447 (with-open-file (*fortran-out
* file
:direction
:output
)
451 #include <sys/select.h>
454 #define MAX_ARRAY(x) (x ? x : 20000)
455 #define CHECK(x) if (!x) {fprintf(stderr,\"xdr failed\"); exit(1);}
462 xdrstdio_create(&xdrs, stdin, XDR_DECODE);
464 (let (res)(dolist (v args
(setq args
(nreverse res
)))
465 (push (get-arg-decl v decls
) res
)))
467 (cond ((atom (cdr v
)) (wt-nl (get-fortran-type(cdr v
)) " " (car v
) ";"))
468 (t (wt-nl (get-fortran-type(cadr v
)) " *" (car v
) "= 0 ;")
469 (wt-nl "u_int " (car v
) "_length = 0;"))))
471 (wt-nl "xdrstdio_create(&xdrs, stdin, XDR_DECODE);")
472 (terpri *fortran-out
*)
476 (unless (atom (cdr v
))
477 (if (and (numberp (third v
))
479 (wt-nl "if ("(car v
)"_length != " (third v
)")"
480 "fprintf(stderr,\"Wrong length for " (car v
)" \");")
482 (if (eq results
(cdr fun
+args
))
483 (wt-nl "if (invoked) exit(0);"))
484 (dolist (v (cdr (assoc '$external decls
)))
485 (wt-nl "{extern int "v
"_ext_();" v
"="v
"_ext_;}"))
488 (wt-nl "/* invoke the function */
490 (wt-nl (car fun
+args
) "_" "(")
491 (do ((v args
(cdr v
)))
496 (if (cdr v
) (wt ",")))
499 (wt-nl "/* write the results out */")
500 (wt-nl "xdrstdio_create(&xdrs, stdout, XDR_ENCODE);")
501 (cond ((equal results
(cdr fun
+args
))
502 (wt-nl "invoked=1 ; goto DO_ARGS;}}"))
505 (wt-xdr (get-arg-decl v decls
) "&xdrs"))
506 (wt-nl "exit(0);}}"))))))
509 (with-open-file (st "joe" :direction
:output
)
510 (let ((xdrs (si::xdr-open st
)))
511 (dolist (v lis
) (si::xdr-write xdrs v
))))
512 (with-open-file (st "joe" )
513 (let ((xdrs (si::xdr-open st
)))
514 (sloop::sloop for w in lis collect
(si::xdr-read xdrs w
)))))
517 /* example of specification of routine
*/
518 make_fortran
(dtrdi(t,ldt
,n
,det
,job
,info
),
519 [[ integer
,ldt
,n
,job
,info
],
520 [double
, t
(ldt,1),det
(2)]],
525 job = 100 + if (t[1,2]=0) then 10 else 11],
526 result=[t,det,info]);
528 make_fortran(dgedi(a,lda,n,ipvt,det,work,job),
529 [ [integer, lda,n,ipvt(n),job],
530 [ double , a(lda,1),det(2),work(n)]],
531 defaults=[lda=length(a),n=length(a[1]),ipvt
=dgeco
(a)[2],det,job=11,work],
532 result=[a,det,ipvt])$
534 make_fortran(dgeco(a,lda,n,ipvt,rcond,z),
535 [[ integer, lda,n,ipvt(n)],
536 [ double , a(lda,1),z(n)],
538 defaults=[lda=length(a),n=length(a[1]),ipvt,rcond=0.0,z],
539 result=[a,ipvt,rcond,z])
543 Maxima 4.130 Sun Nov 12 15:59:51 CST 1989 (with enhancements by W. Schelter).
544 (C1) make_fortran(dtrdi(t,ldt,n,det,job,info),
545 [[ integer ,ldt,n,job,info],
546 [double, t(ldt,1),det(2)]],
551 job = 100 + if (t[1,2]=0) then 10 else 11],
552 result=[t,det,info]);
555 (C2) dtrdi(matrix([11.00,12.0],[0.0,13.0]));
557 [ 0.090909090909090912 - 0.083916083916083919 ]
559 [ 0.0 0.076923076923076927 ]
561 [1.4300000000000002, 2.0], 0]